首页 > 其他 > 详细

JVM内存模型

时间:2021-01-08 18:24:59      阅读:21      评论:0      收藏:0      [点我收藏+]

研究了一波JVM,自己把手头的资料做一些整理。

一,JVM演变史

技术分享图片

图出处:https://www.cnblogs.com/xiaofuge/p/14244755.html

图中大概可以看出一个梗概,那就是方法区(永久代)的逐渐消亡,从主内存中逐渐变到本地内存中。

Hotspot中 方法区的变化:

  1. jdk1.6及之前:有永久代(permanent generation),静态变量存放在 永久代上。
  2. jdk1.7:有永久代,但已经逐步“去永久代”,字符串常量池、静态变量移除,保存在堆中。
  3. jdk1.8及之后:无永久代,类型信息、字段、方法、常量保存在本地内存的元空间,但字符串常量池、静态变量仍留在堆空间。
那为什么要这么做呢?

原来方法区存储了类的元数据信息和各种常量,而且他也受GC的管理,而GC的目标理应当是对这些类型的卸载和常量的回收。但由于这些数据被类的实例引用,卸载条件变得复杂且严格,回收不当会导致堆中的类实例失去元数据信息和常量信息。因此,回收方法区内存不是一件简单高效的事情,往往GC在做无用功。另外随着应用规模的变大,各种框架的引入,尤其是使用了反射,动态代理等字节码生成技术的框架,对于方法区的大小设置无法把控,会导致方法区内存占用越来越大,最终OOM,那把方法区剔除出来是当务之急。

二,JVM模型拆检

JVM内存模型可以分为两个部分,堆和方法区(元空间)是所有线程共有的,而虚拟机栈,本地方法栈和程序计数器则是线程私有的。为了形象说明,参见下图:

技术分享图片

图出处:https://www.cnblogs.com/yanl55555/p/13323128.html

1. 程序计数器
  • 较小的内存空间、线程私有,记录当前线程所执行的字节码行号。
  • 在虚拟机的模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、异常处理、线程恢复等基础功能都需要依赖计数器完成。
  • 这一块区域没有任何 OOM 定义
2. 本地方法栈(Native Stack)

与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的java方法服务,而本地方法栈则是为Native方法服务,普通开发可以忽略。JDK1.8 HotSpot虚拟机直接就把本地方法栈和虚拟机栈合二为一。

3. 虚拟机栈(JVM Stack)
  • java方法执行的内存模型——栈帧:用于存储局部变量表(包括参数)、操作栈、方法出口等信息。每个方法被调用到执行完的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。生命周期与线程相同,无线程安全的顾虑,因为都是线程单独私有的。

  • -Xss设置每个线程堆栈的大小。一般情况下256K是足够了。

技术分享图片

局部变量表:
  • 存放方法参数和方法内部定义的局部变量(包括对象引用)。注意如果是成员变量,或者定义在方法外对象的引用,它们存储在堆中,涉及到线程共有的都在堆中,如果都是私有,也就没线程安全这一说了。

  • 局部变量表的容量以变量槽slot为最小单位,每个变量槽都可以存储32位长度的内存空间,例如boolean、byte、char、short、int、float、reference。其中64位长度的long和double类型的数据会占用2个空间,同时slot支持复用。

  • 局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量是完全确定的,在运行期间栈帧不会改变局部变量表的大小空间。

局部变量表:

JVM内存模型

原文:https://www.cnblogs.com/zhou-yuan/p/14252272.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!