天天看点

深入理解 Java 虚拟机 学习:Java虚拟机内存区域

Java 虚拟机 其他相关博客

深入理解 Java 虚拟机 学习:总结 GC 的知识点,面试问 GC 有这一篇就足够了

深入理解 Java 虚拟机 学习:对象访问

一.运行时数据区域

Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程的启动和结束而建立和销毁。根据《 Java 虚拟机规范(第二版)》的规定,Java 虚拟机所管理的内存将会包含以下几个运行时数据区域

1.运行时数据区域图
深入理解 Java 虚拟机 学习:Java虚拟机内存区域
2.程序设计器:
  • 较小的内存空间
  • 作用:当前线程执行的字节码的型号指示器
  • 工作:通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等基础功能
  • 线程私有:每条线程都有一个独立的程序设计器,各条线程之间的计数器互不影响,独立存储
3.Java 虚拟机栈
  • 线程私有:生命周期与线程相同
  • 描述:Java 方法执行的内存模型,每个方法被执行的时候都会同时创建一个栈帧,用于存储局部变量表,操作栈,动态链接,方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈种从入栈到出栈的过程
  • 栈:大多数说的栈就是虚拟机栈,或者说是虚拟机栈种的局部变量表部分
  • 局部变量表:基本数据类型,对象引用和 returnAddress 类型
  • 其中64位长度的 long 和 double 类型的数据会占用2个局部变量空间,其余的数据类型只占用1个。局部变量表所需要的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小
4.本地方法栈
  • 1.作用:与虚拟机栈所发挥的作用是非常相似的
  • 2.和虚拟机栈的区别: 虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的 Native 方法服务,有的虚拟机会直接把本地方法栈和虚拟机栈合二为一。
5.Java堆
  • Java虚拟机中管理中,内存最大的一块
  • 线程共享:Java 堆是被所以线程共享的一块内存区域,在虚拟启动时创建
  • 作用:用来存放对象实例,几乎所以的对象实例都在这里分配
  • GC堆:Java堆是体积收集器管理的主要区域,因此很多时候也被称之为“GC堆”
  • 内存回收角度:由于现在收集器基本都是采用分代收集算法,所以 Java 堆中还可以细分成:新生代和老年代,再细致一点的有 Eden 空间,From Survivor 空间,To Survivor 空间等
  • 内存分配角度:线程共享的Java堆中可能划分出多个线程私有的分配缓冲区,不过怎么划分,都与存放内容无关,无论那个区域存储的都依然是对象实例,进一步划分是更好地回收内存,或者更快的分配内存
6.方法区
  • 永久代:很多人愿意把方法区称为 “永久代”,本质上来讲两者并不等价,仅仅时因为 HotSpot 虚拟机的设计团队选择把 GC 分代收集扩展至方法区,或者说使用永久代来实现 方法区而已,对于其他虚拟机(如 BEA JRockit ,IBM J9等)来说时不存在永久代的概念的
  • 线程共享:与Java堆一样,是各个线程共享的内存区域
  • 作用:用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据
  • Java 虚拟机规范对这个区域的限制还是比较宽松的,除了和 Java 堆一样不需要连续的内存和可以选择固定大小或者可以扩展外,还可以选择不实现垃圾收集。垃圾收集在这个区域还是比较少出现的,但并非数据进入方法区就如永久代的名字一样 “永久”存在了,这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载