JVM内存模型——堆及垃圾回收.md

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014453515/article/details/85777006

本节简单梳理下JVM运行时堆上的内存模型,以及垃圾回收的的知识点。

堆是JVM运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。

非堆内存

Java 虚拟机具有一个由所有线程共享的方法区。方法区属于非堆内存。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码。它是在 Java 虚拟机启动时创建的。
方法区在逻辑上属于堆,但 Java 虚拟机实现可以选择不对其进行回收或压缩。与堆类似,方法区的大小可以固定,也可以扩大和缩小。方法区的内存不需要是连续空间。
盗用的图,侵删

1.堆的分区

Java Heap分为2块,Permanent Space 和 Heap Space。
名词解释:
Heap space:存放Instance。分为两块,新生代和老年代。
Permanent space:即永久代。就是说是永久保存的区域,用于存放Class和Meta信息,Class在被Load的时候被放入该区域,GC(Garbage Collection)不会对Permanent space进行清理.

1.1 新生代

新生代又可以划分为一个Eden区和两个Survivor(幸存)区。
按照规定,新对象会首先分配在Eden中(如果对象过大,比如大数组,将会直接放到老年代)。在GC中,Eden中的对象会被移动到survivor中,直至对象满足一定的年纪(定义为熬过minor GC的次数),会被移动到老年代。

新生代的容量划分:
Eden : Survivor1: Survivor2= 8:1:1

1.2. 新生代的垃圾回收

对象创建后,在新生代的存活过程:

  1. 绝大多数刚创建的对象会被分配在Eden区,其中的大多数对象很快就会消亡。
  2. Eden区是连续的内存空间,因此在其上分配内存极快;最初一次,当Eden区满的时候,执行Minor GC,将消亡的对象清理掉,并将剩余的对象复制到一个存活区Survivor0(此时,Survivor1是空白的,两个Survivor总有一个是空白的);
  3. 下次Eden区满了,再执行一次Minor GC,将消亡的对象清理掉,将存活的对象复制到Survivor1中,然后清空Eden区;
  4. 将Survivor1中消亡的对象清理掉,将其中可以晋级的对象晋级到Old区,将存活的对象也复制到Survivor2区,然后清空Survivor1区;
    当两个存活区切换了几次(HotSpot虚拟机默认15次,用-XX:MaxTenuringThreshold控制,大于该值进入老年代,但这只是个最大值,并不代表一定是这个值)之后,仍然存活的对象(其实只有一小部分,比如,我们自己定义的对象),将被复制到老年代

Yong GC的垃圾回收的方式就是著名的“停止-复制(Stop-and-copy)”清理法(将Eden区和一个Survivor中仍然存活的对象拷贝到另一个Survivor中)。特点:

  • Eden区是连续的空间
  • 两个Survivor至少有一个是空白的,以接收下一次Yong GC结束后Eden区和另一个Survivor存活下来的对象
  • 当Yong GC 时,如果Eden有大对象存活,Survivor放不下时,直接进入老年代。

3. 老年代

年老代(Old Generation):对象如果在年轻代存活了足够长的时间而没有被清理掉(即在几次Young GC后存活了下来),则会被复制到年老代,年老代的空间一般比年轻代大,能存放更多的对象,在年老代上发生的GC次数也比年轻代少。当年老代内存不足时,将执行Major GC,也叫 Full GC。
如果对象比较大(比如长字符串或大数组),Young空间不足,则大对象会直接分配到老年代上(大对象可能触发提前GC,应少用,更应避免使用短命的大对象)。

提问环节

##1. 什么时候触发Young GC(也叫作Minor GC)
伊甸区装不下新对象的时候

2.什么时候触发full GC

  • 老年代空间不足
  • 永久代空间不足 1.8 后永久代换成了元数据区,特点是动态扩容
  • YGC出现promotion failure
    promotion failure发生在Young GC, 如果Survivor区当中存活对象的年龄达到了设定值,会就将Survivor区当中的对象拷贝到老年代,如果老年代的空间不足,就会发生promotion failure, 接下去就会发生Full GC.
  • 显示调用System.gc

3.什么样的对象能被回收?

GC Root不可达。判断GC Root是否可达的算法:可达性分析算法。
通过一系列被称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots对象没有任何引用链相连,就认为GC Roots到这个对象是不可达的,判定为不可用对象,可以被回收。

4.GC Root有哪些,什么样的变量能成为GC Root?

  • 虚拟机栈(栈帧中的本地变量表)中的引用的对象;
  • 方法区中类静态属性引用的对象;
  • 方法区中常量引用的对象;
  • 本地方法栈中JNI(一般说的Native方法)的引用的对象。

猜你喜欢

转载自blog.csdn.net/u014453515/article/details/85777006