GC是在什么时候,对什么东西,做了什么事情?
1.在什么时候:
eden满了minor gc,升到老年代的对象大于老年代剩余空间full gc,或者小于时被HandlePromotionFailure参数强制full gc;gc与非gc时间耗时超过了GCTimeRatio的限制引发OOM,调优诸如通过NewRatio控制新生代老年代比例,通过MaxTenuringThreshold控制进入老年前生存次数等....
2.对什么东西:
从root搜索不到,而且经过第一次标记、清理后,仍然没有复活的对象。
那些对象可以作为GC Roots? 虚拟机栈(栈帧中的本地变量表)中的引用的对象 方法区中的类静态属性引用的对象 方法区中的常量引用的对象 本地方法栈中JNI(Native方法)的引用对象
3.做了什么事情:
HotSpot JVM (下简称JVM)的内存管理 JVM将堆分成了 二个大区 Young 和 Old 如下图:
<img src="https://pic3.zhimg.com/41b0c5f5c0f2f30ed5ef5f699597511e_b.png" data-rawwidth="556" data-rawheight="326" class="origin_image zh-lightbox-thumb" width="556" data-original="https://pic3.zhimg.com/41b0c5f5c0f2f30ed5ef5f699597511e_r.png">而Young 区又分为 而Young 区又分为 Eden、Servivor1、Servivor2, 两个 Survivor 区相对地作为为From 和 To 逻辑区域, 当Servivor1作为 From 时 , Servivor2 就作为 To, 反之亦然 关于为什么要这样区分Young(将Young区分为Eden、Servivor1、Servivor2以及相对的From和To ),这要牵涉到JVM的垃圾回收算法的讨论。 1)因为引用计数法无法解决循环引用问题,JVM并没有采用这种算法来判断对象是否存活。 2)JVM一般采用GCRoots的方法,只要从任何一个GCRoots的对象可达,就是不被回收的对象 3)判断了对象生死,怎么进行内存的清理呢? 4)标记-清除算法,先标记那些要被回收的对象,然后进行清理,简单可行,但是①标记清除效率低,因为要一个一个标记和清除②造成大量不连续的内存碎片,空间碎片太多可能会导致当程序在以后的运行过程中需要分配较大对象的时候无法找到足够的连续内存而不得不触发另一次垃圾收集动作。 5)采用复制收集算法:将可用内存按照容量分为大小相等的两块,每次只是使用其中的一块。当这一块的内存用完了,就将可用内存中 <img src="https://pic3.zhimg.com/55e852328b19760c09569f1f90637376_b.png" data-rawwidth="836" data-rawheight="146" class="origin_image zh-lightbox-thumb" width="836" data-original="https://pic3.zhimg.com/55e852328b19760c09569f1f90637376_r.png"> <img src="https://pic1.zhimg.com/212cd1165d947e182f1a71bcdd40ab60_b.png" data-rawwidth="832" data-rawheight="510" class="origin_image zh-lightbox-thumb" width="832" data-original="https://pic1.zhimg.com/212cd1165d947e182f1a71bcdd40ab60_r.png"> <img src="https://pic1.zhimg.com/2ae24424f47c4830dad9734772aa6e28_b.png" data-rawwidth="841" data-rawheight="374" class="origin_image zh-lightbox-thumb" width="841" data-original="https://pic1.zhimg.com/2ae24424f47c4830dad9734772aa6e28_r.png"> 上面的过程就解释了为什么我们的Yong内存需要分为三块,Eden,Survivor1,Survivor2以及FROM TO相对使用的用法 <img src="https://pic2.zhimg.com/618110e6a18cac3f20f2b3837b188d4d_b.png" data-rawwidth="573" data-rawheight="306" class="origin_image zh-lightbox-thumb" width="573" data-original="https://pic2.zhimg.com/618110e6a18cac3f20f2b3837b188d4d_r.png"> 因此当Eden区满的时候 GC执行,这时会将 Eden 区和 From 区中还被引用的对象会被移到 To区 ,个别大对象和部分From对象在To已满的情况下会被放到Old区,如下图: 因此当Eden区满的时候 GC执行,这时会将 Eden 区和 From 区中还被引用的对象会被移到 To区 ,个别大对象和部分From对象在To已满的情况下会被放到Old区,如下图: <img src="https://pic2.zhimg.com/35ed96d1c1635b589883094b82459791_b.png" data-rawwidth="543" data-rawheight="298" class="origin_image zh-lightbox-thumb" width="543" data-original="https://pic2.zhimg.com/35ed96d1c1635b589883094b82459791_r.png">HotSpot VM 内存堆的两个Servivor区HotSpot VM 内存堆的两个Servivor区