JVM内存模型分析

520 阅读4分钟


JVM内存模型图

                                                               (图1-1)

内存模型分为5块区域

  • 虚拟机栈  
  • 本地方法栈
  • 方法区(元空间)
  • 程序计数器


首先:假设有一个Hello.java类,通过javac 编译为Hello.class字节码文件,通过类装载子系统,加载进JVM虚拟机中


方法区

方法区会加载类的常量,静态变量,类元信息(方法名,修饰符等等)

虚拟机栈

JVM会为每一个线程在虚拟机栈中开辟一小块区域,存放线程中的数据(程序计数器和方法栈帧),栈是先进后出,对于执行引擎来说,只有栈顶的栈帧是有效的,被称为当前栈帧,所关联的方法被称为当前方法

栈帧中又分为四块区域

  1. 局部变量表:是一组用于存放方法参数和方法内局部变量的存储空间,索引0位置,存放this,也就是当前对象地址
  2. 操作数栈:操作数在程序运行中临时存放数据做运算的一块区域
  3. 动态链接:将符号引用在程序运行中转化为直接应用,也就是说,一个方法在调用另一个方法的时候,需要知道另一个方法的信息,栈中存有堆中对象的引用地址,而堆中对象是根据方法区中的类信息所创建,也就可以找到另一个方法的信息,达到调用的目的
  4. 方法出口:存放调用该方法的程序的位置((图1-2)code列的位置),结束当前方法的时候,可以回到上一方法,继续运行


PS:javap -c指令可以对class文件进行反编译,生成如图文件,可以看出底层代码执行顺序,程序计数器中存放就是code列的值,通过值找到程序运行的位置

Java字节码指令大全

www.cnblogs.com/longjee/p/8…


                                                              (图1-2)

本地方法栈

Java调用本地native方法的时候会将方法信息压入本地方法栈



新建对象都会放入堆区中Eden,堆区的对象都是线程共享的。

堆被划分为新生代和老年代两个区域,其中新生代又被划分为Eden,From survivor ,

To survivor 三个区域

老年代占据2/3,新生代占据1/3

新生代中 Eden 占据 8/10,From survivor 和 To Survivor 各自占据 1/10

这样划分是为了JVM能够更好的管理堆内存中的对象

对象分为对象头和实例数据

对象头



堆是内存分配中最大的一块区域,也是GC重点关注的区域,GC回收前要判断堆中哪些对象存活,哪些不可能再被引用,需要回收。GC分为两种  minor GC 和 Full GC。

minor GC为新生代收集垃圾,Full GC为老年代收集垃圾

minor GC会在Eden区满的时候被触发,清理没有被GC Root引用链所引用的对象

剩余存活的对象,通过复制算法,进入survivor区中的From,并且对象头中的分代年龄+1,

第二次再触发时,清理Eden和From区中的对象,仍然通过复制算法,把两区域中存活的对象迁移到To区,分代年龄+1

第三次触发,会把Eden区和To区存活对象迁移到From区,分代年龄+1

Java中的对象通常不会长久存活,所以需要GC负责回收,新生代是GC回收最频繁的区域。

分代年龄达到15的对象,会被移动到老年代(spring管理的Bean,程序初始化时的一些对象)

--一些较大的对象,可能会直接被放入老年代

老年代被放满之后会停掉程序线程,去执行Full GC,老年代的GC采用标记-清除算法

ps:JDK自带jvisualvm指令,可以打开 Java VisualVM,jvisualvm安装visual GC插件可以对程序运行中的GC进行分析,图像化直观展示

GC 算法

blog.csdn.net/cainiao_stu…


JAVA中使用可达性分析来判断对象是否存活

可达性分析:以若干个GC Root为根节点,从节点向下搜索,如果一个对象没有被若干条引用链所引用到,则证明这个对象不可达。

GC Root根节点:线程栈的本地变量,静态变量,本地方法栈的变量