JVM运行时内存区域

 

注:学习笔记。

JVM运行时内存区域

1、程序计数器

1)当前线程所执行的字节码的行号指示器。记录线程执行位置。

2)线程私有:Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现,也就是说,在同一时刻一个处理器内核只会执行一条线程,处理器切换线程时并不会记录上一个线程执行到哪个位置,所以为了线程切换后依然能恢复到原位,每条线程都需要有各自独立的程序计数器。

3)JVM规范中唯一没有规定OutOfMemoryError情况的区域。程序计数器存储的是字节码文件的行号,而这个范围是可知晓的,在一开始分配内存时就可以分配一个绝对不会溢出的内存。

4)如果正在执行的是Native 方法,则这个计数器值为空。Native方法大多是通过C实现并未编译成需要执行的字节码指令,也就不需要去存储字节码文件的行号了。

2、java虚拟机栈

1)Java虚拟机栈也是线程私有的,它的生命周期与线程相同(随线程而生,随线程而灭)

2)如果线程请求的栈深度大于虚拟机所允许的深度,将抛出*Error异常;如果虚拟机栈可以动态扩展,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常;(当前大部分JVM都可以动态扩展,只不过JVM规范也允许固定长度的虚拟机栈)

3)Java虚拟机栈描述的是Java方法执行的内存模型:每个方法执行的同时会创建一个栈帧。对于我们来说,主要关注的stack栈内存,就是虚拟机栈中局部变量表部分。

4)局部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。并且在Java编译为Class文件时,就已经确定了该方法所需要分配的局部变量表的最大容量。

5)局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)「String是引用类型」,对象引用(reference类型) 和 returnAddress类型(它指向了一条字节码指令的地址)。

3、本地方法栈

虚拟机栈为虚拟机执行java方法(也就是字节码服务),而本地方法栈为虚拟机使用的native方法服务。也会抛出*Error异常和OutOfMemoryError异常。

4、Java堆(java heap)

1)对大多数应用来说,java堆是java虚拟机所管理的内存中最大的一块。

2)此内存区域唯一的目的就是存放对象实例,几乎所有的对象实例以及数组都要在这里分配内存。

3)java堆是垃圾收集器主要管理区域,为了更好的回收或者分配内存,java堆还可以细分为:新生代和老年代;再细致一点的有Eden空间、From Survivor空间、To Survivor空间等。从内存分配的角度看,线程共享的java堆中可能划分出多个线程私有的分配缓冲区。

4)在物理上可以是不连续的内存空间,只要逻辑上连续。

5)堆内存一般可扩展(通过-Xmx和-Xms控制)。

6)如果堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。

5、方法区

1)方法区和java堆一样是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据;

2)方法区是线程安全的。由于所有的线程都共享方法区,所以,方法区里的数据访问必须被设计成线程安全的。

3)方法区的大小不必是固定的,JVM可根据应用需要动态调整。同时,方法区也不一定是连续的,方法区可以在一个堆(甚至是JVM自己的堆)中*分配。

4)方法区也可被垃圾收集(但条件苛刻),当某个类不在被使用(不可触及)时,JVM将卸载这个类,进行垃圾收集

5)当方法区无法满足内存需求时,将抛出OutOfMemoryError异常。

6、运行时常量池(Runtime Constant Pool)

1)运行时常量池是方法区的一部分。

2)class文件中除了有类的版本、字段、方法、接口等信息之外,还有一项信息是常量池(Constant Pool Table),用于存放编译时生成的各种字面量和符号引用,这部分内容将在类加载之后存放到方法区的运行时常量池中。

3)相对于class文件常量池,运行时常量池具备动态性;处理预置class文件中的常量池的内容,运行期间也可将新的常量放入运行时常量池中。

7、直接内存(堆外内存)

1)直接内存并不是虚拟机运行时数据区的一部分。

2)NIO中使用通道(Channel)和缓冲区(Buffer)的I/O方式,可以使用Native函数库直接分配堆外内存,然后通过存储在java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。避免了在java堆和Native堆中来回复制数据,提高性能。

3)直接内存不会受到java堆大小的限制,但受物理机总内存的限制。

参考资料:《深入理解java虚拟机》