1.概述
垃圾回收,顾名思义是将弃用的对象进行回收处理,释放内存空间,防止大量无用对象占用内存空间,导致内存泄露。
2.对象存储在什么地方?
进行垃圾回收,首先要确认对象是存放在什么地方。
初学java时,你一定听过对象是存放在堆内存的。堆内存里其实也分为不同区域,堆内存分为两大块,一个是Old区,一个是Young区 Young区分为两大块,一个是Survivor区(S0+S1),一块是Eden区 S0和S1一样大,也可以叫From和To。
名称 | 介绍 |
---|---|
Old区 | Old区又称老年代,存储了大量存活时间久的对象, 或者是通过担保机制的超过Young区大小的大对象 |
Young区 | Young区又称新生代,存储了新创建的对象和创建时间不长的对象 ,Young区又分为Eden区和Survivor区(S0+S1),Eden区存储了新创建的对象,Survivor区存储了至少经过一次GC的对象 |
3.对象在堆内存的创建过程
一般情况下,新创建的对象都会被分配到Eden区,一些特殊的大的对象会直接分配到Old区(担保机制)。
Minor GC:新生代
Major GC:老年代
Full GC: 新生代+老年代
4.如何找到一个垃圾对象?
要想进行垃圾回收,得先知道什么样的对象是垃圾。
4.1 引用计数法
对于某个对象而言,只要应用程序中持有该对象的引用,就说明该对象不是垃圾,如果一个对象没有任何指针对其引用,它就是垃圾。
缺点:如果AB相互持有引用,导致永远不能被回收。
4.2 可达性分析
通过GC Root,开始向下寻找,看某个对象是否可达,如果对象不可达,则判定为垃圾对象
4.3 GC Root
GC Roots就是堆外指向堆内的一些引用,通过GC Roots向下查找,向下查找的链条称为引用链。当一个对象没有引用链,则判定为垃圾对象。
哪些对象引用可以称为GC Roots
1.虚拟机栈栈帧中对象的引用。
2.方法区中类静态属性对象的引用。
3.方法区中常量对象的引用。
4.本地方法栈中JNI对象的引用。
5.何时进行垃圾回收?
5.何时进行垃圾回收?
GC是由JVM自动完成,无法确定具体时间。
可以通过调用System.gc()方法通知JVM进行一次垃圾回收,但是System.gc()只是通知JVM进行垃圾回收,何时进行垃圾回收由JVM决定。
一般垃圾回收场景
1.Eden区或者S区内存空间不足,触发Minor GC。
2.Old区内存空间不足,触发Major GC。
3.System.gc()。
6.垃圾回收算法
6.1 标记-清除(Mark-Sweep)
找出需要进行回收的对象,将其标记出来后进行清理
缺点
- 需要将所有对象扫描一遍,才能进行垃圾回收,耗时长。
- 会产生内存碎片,后续增加大对象时,可能因为没有合适的内存存储,再次触发垃圾清理。
6.2 标记-复制(Mark-Copying)
将内存空间分为两块相等的区域,只使用一块区域。当其中一块内存用完后,就会触发垃圾清理,将存活对象复制到另一块内存中,再将内存清空。
缺点:内存利用率不高
6.3 标记-整理(Mark-Compact)
将存活对象向一端移动,然后对不可达对象进行清理
6.4 分代收集算法
Young区:标记-复制算法。对象创建后,生命周期可能较短,采用标记-复制算法较为合适
Old区:标记-清除或标记整理。Old区对象生命周期较长,清除或整理比复制效率高
分代算法根据每个区的对象特点采用不同的算法,提升垃圾回收效率。