一、概念
虚拟机:通过软件模拟的具有完整硬件功能的运行在一个完全隔离环境中的完整操作系统。
JVM:软件虚拟Java字节码指令集。
HoSpot是Java默认的虚拟机。
二、Java内存区域与内存溢出异常
Java虚拟机所管理的内存包括如下几个运行时数据区域:
(1)线程私有区域(随线程的创建与销毁而创建与销毁):程序计数器、虚拟机栈、本地方法栈。
(2)线程共有区域:Java堆、方法区、运行时常量池。
1、程序计数器(线程私有)
(1)程序计数器是一块比较小的内存空间,它可以看作是当前线程所执行字节码的行号指示器。
(2)若当前线程执行的是Java方法,程序计数器记录的是正在执行的虚拟机字节码指令的地址(即代码行号);如果执行的是本地方法,则计数器值则为空。
(3)程序计数器是唯一一个在JVM规范中没有OutOfMemoryError(OOM)出现的区域。
2、虚拟机栈(线程私有)
(1)虚拟机栈描述的是Java方法执行的内存模型:每个方法执行时都会在虚拟机栈中创建一个栈帧用于存储局部变量表、方法出口等信息。
(2)虚拟机栈的生命周期和线程相同。
(3)局部变量表:局部变量表中存放编译器可知的八大基本数据类型及对象的引用(在之前我们一直所谓的栈即就是局部变量表)
(4)报错信息:该区域会报出两种错误信息:StackOverflowError、OutOfMemoryError。
(-Xss 用来指定虚拟机栈深度)
A. 如果线程请求的深度 > 虚拟机所允许的深度,则会报 StackOverflowErro错误(多见于单线程中)。
B. 如果虚拟机动态扩展无法申请到足够内存,则会报出OutOfMemoryError错误(多见于多线程)。
3、本地方法栈(线程私有)
虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则是服务本地方法(native)。
HotSpot虚拟机将本地方法栈与虚拟机栈合二为一。
方法)
4、Java堆
(1)Java堆线程共享,在JVM启动时创建,存放的都是对象实例。
JVM:要求所有的对象实例以及数组都在Java堆上存放。
(2)Java堆可处于物理上不连续的区域,Java堆一般来说都是可扩展的。
(-Xms:设置堆的最小值 -Xmx:设置堆的最大值)
(3)如果堆中无足够内存完成对象实例化时,并无法再扩展时,会抛出OutOfMemoryError异常信息,此时OutOfMemoryError可包含两种信息
A. 内存泄漏:泄露对象无法被GC。
B. 内存溢出:该对象确实还应该存活;应该对比物理内存查看当前Java堆是否还应该扩容或者缩短对象存活时间.
(一般可通过扩容方法来区分是内存泄漏还是内存溢出,将堆内存扩容一倍,若解决问题则是内存溢出,反之亦然。)
5、方法区
(1)线程共有,jdk1.8之前称之我永久代,jdk1.8以后为元空间。
(2)方法区存储已经被JVM加载的类信息、常量、静态变量。
(3)此区域也会进行垃圾回收,主要针对常量池的回收以及类型卸载。
(4)方法区无法满足内存需求时,抛出OutOfMemoryError异常。
6、运行时常量池
(1)存放字面量以及符号引用(字面量:直接量,如字符串、final常量、基本数据类型的值;符号引用:类和结构的完全限定名、字段的名称和描述符、方法的名称和描述符)
(2)运行时常量池是方法区的一部分,自然受到方法区内存的限制,当常量无法再申请到内存时或抛出OutOfMemoryError异常。