“Java”内存区域-“堆与栈”

  本文是我阅读周志明老师《深入理解Java虚拟机-JVM高级特性与最佳实战》章节2.2的学习笔记。更多内容,请参考原书。

  Java虚拟机在执行Java程序时会将其所管理的内存划分为若干个不同的数据区域,这些区域有各自的用途及生命周期。具体而言包括以下几个区域。

1. 程序计数器

  一块较小的内存空间,可视作当前线程所执行的字节码的行号指示器。主要用途是选取该线程下一条需要执行的字节码指令。

  每个线程有一个独立的程序计数器,各个线程的计数器之间互不影响,独立存储。这样的内存区域也被称为“线程私有”的内存。

  若线程在执行Java方法,则计数器记录正在执行的虚拟机字节码指令的地址;若正在执行Native方法,则计数器为“Undefined”。

2. 虚拟机栈

  同样是线程私有的,其生命周期与线程同步。虚拟机栈描述Java方法执行的内存模型,每个方法在执行时都会创建一个Stack Frame,其中存储了局部变量表,操作数栈,动态链接,方法出口等信息。每个方法从调用到执行完成的过程,即对应着一个Stack Frame在虚拟机栈中从入栈到出栈的过程。

  局部变量表存放编译器可知的各种基本数据类型,对象引用及Return Adress类型。局部变量表所需的内存空间在编译期间完成分配,也就是说进入一个方法时,其Stack Frame中的局部变量空间是确定的,在运行期间不会改变。

  当线程请求的栈深度大于虚拟机所允许的深度,即抛出“StackOverflowError”;若虚拟机可动态扩展(当前大部分虚拟机都可扩展),若扩展时无法申请到足够的内存,则抛出“OutOfMemoryError”。

3. 本地方法栈

  主要为虚拟机使用到的Native方法服务,其作用与虚拟机栈类似。

4. Java堆

  Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,是虚拟机管理的内存中最大的一块。基本来说,所有的对象实例及数组都要在这里分配内存。某个对象分配的空间大小是另一个问题。

  Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为“GC堆”(Garbage Collection Heap)。堆上各个区域的分配回收等是GC问题。

  Java堆只需是逻辑上连续的即可,不必物理上连续。目前主流的虚拟机都将堆实现成了可扩展的(-Xmx,-Xms,即最大堆和初始堆大小)。若堆需要扩展而无法扩展时,也会抛出“OutOfMemory-Error”。

5. 方法区

  Method Area也是被各个线程共享的内存区域,用去存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。逻辑上来说属于堆的一部分。

  关于方法区,运行时常量池及直接内存等的相关内容,请参考原书。

posted @ 2016-06-11 11:35  yunhe  阅读(408)  评论(0编辑  收藏  举报