垃圾回收算法

1、主要发生位置
(1)GC主要发生于堆和方法区
(2)次数上讲,频繁young区,较少old区,基本不元空间
**Minor GC:**回收新生代,发生在young区,因为新生代对象存活的时间比较少,因此回收的次数比较频繁,执行速度比较快。
Full GC:回收新生代和老年代,因为老年代对象存活的时间比较久,因此回收的频率较少,执行的速度比较慢。
Full GC原因:
(1)调用System.gc()方法,会显式触发GC,但是虚拟机不一定会去执行。
(1)老年代不足的原因:比较大的字符串或者数组直接分配的老年代中(新生代的剩余空间不足于存放),有大量长期存活的对象到老年代。
(2)采用复制算法的话,需要用老年代作为空间担保,担保失败的话就会触发full GC。
(3)当系统中要
加载的类、反射的类和调用的方法
过于多的时候,永久代会被占满,就会触发。
永久代中存放的是类信息、常量、静态变量

2、垃圾回收相关算法
判断对象是否存活,有两种方式:引用计数算法和可达性分析算法
(1)引用计数算法:对每一个对象保存一个整形的程序计数器属性,用来记录对象被引用的情况。
对于一个对象A,如果有一个对象引用了A,则A的引用计数器加1,引用失效就减1,如果引用计数器为0,就表示对象没有被引用。
优点:实现简单,垃圾判定效果高,回收没有延迟性。
缺点:增加存储空间开销,更新引用计数器增加了时间开销,无法解决循环引用问题,因此不用这个算法。
(2)可达性分析算法:以根对象集合(GC Roots)为起点,从上到下的方式搜索被根对象集合所连接的对象目标是否可达。使用可达性分析算法之后,内存中存活的对象都会直接或间接被跟对象集合所连接,搜索走过的路径叫做引用链
如果目标对象没有任何引用链相连,则是不可达的,意味着该对象已死亡,可以被垃圾回收。
(3)三色标记法
三色标记法把遍历对象图过程中遇到的对象分为3种颜色
白色:尚未访问过
灰色:本对象访问过,但是本对象所引用的其他对象没有被访问过
黑色:本对象已经访问过,并且本对象所引用的对象都被访问过。
当STOP THE WORLD的时候,对象之间的引用不会发生变化,所以可以完成标记。
1.初始时,所有对象都在白色集合中
2.把GC ROOTS所引用的直接对象放到灰色集合中
3.从灰色集合中获取对象
把本对象所引用的其他对象都放到灰色集合当中
把本对象放到黑色集合当中
4、重复步骤3,直到灰色集合为空
5、此时白色集合中的对象就是GC Roots不可达,可以被回收的对象。
2.1、GC Roots包含以下几类元素:GC Roots是一组活跃对象的引用,而不是对象(放在set中)

~虚拟机栈中局部变量表中引用的对象(各个被线程中调用方法的参数、局部变量等)
~本地方法栈内方法引用的对象
~方法区中静态属性引用的对象
~字符串常量池中引用的对象
~堆空间中类静态属性引用的对象

2.2、注意
(1)如果使用可达性分析算法,那么分析工作必须保证在一个保证一致性的快照中进行,这点不满足的话那么分析结果的准确性也无法保证。
(2)这点也是导致GC时必须进行“stop the WORLD”的一个重要原因。stw

3.1、对象的finalization机制
由于finalize()方法的存在,虚拟机中的对象一般处于三种状态
(1)可触及的:从根节点开始,可以到达这个对象
(2)可复活的:对象的所有引用都被释放,但是对象可能在finalize()方法复活
(3)不可触及的:对象的finalize()被调用,但是对象没有复活,那么就是处于不可触及状态,也不会复活,因为finalize()方法只会被调用一次。

4.1、标记-清除算法(Mark-Sweep)
(1)当堆中的有效内存空间被用完的时候,就会停止整个程序(stw),然后就会进行两项工作,一是标记,二是清除
(2)标记:Collector从引用根节点开始遍历,标记所有被引用的对象,一般是在对象的header中记录为可达对象。
(3)清除:Collector对堆内存从头到尾进行线性遍历,如果发现某个对象在其header中没有标记为可达对象,那么就将他们回收。
在这里插入图片描述
缺点:
(1)标记清除算法的效率不高
(2)进行GC的时候需要停止整个应用程序,用户体验差
(3)这种方式清理出来的空闲内存不是连续的,产生内存碎片,需要维护一个空闲列表。
到底什么是清除?
这里所谓的清除不是真的置空,而是要把清除的对象地址保存在空闲的地址列表里,当有新的对象加载时,如果垃圾回收的位置足够,就覆盖原有的地址。

4.2、复制算法
核心思想:将活着的内存空间分为2块,每次只使用一块,在垃圾回收的时候把正在使用的内存中存活的对象复制到未被使用的内存当中,之后清除正在被使用内存中所有的对象,交换两个内存的角色,完成垃圾回收。
在这里插入图片描述
优点:
(1)没有标记和清除过程,实现简单,运行高效。
(2)复制过去以后保证空间的连续性,不会出现碎片化
缺点:
(1)此算法的缺点明显,因为要2倍的内存空间
(2)对于G1这种需要拆分成大量region的GC,复制而不是移动,意味着GC要维护region之间对象的引用关系,不管是内存占用还是时间开销都不小。
特别的:
如果系统中的垃圾对象很多,复制算法需要复制的存活对象数量并不太大,或者非常低才行,就适合新生代。

4.3、标记压缩算法(Mark-Compact)
(1)第一阶段和标记-清除算法相同,都是从根节点开始标记所有被引用的对象。
(2)第二阶段把所有存活的对象压缩到内存的一端,按顺序排放。
(3)之后,清理边界外的所有空间。

标记压缩算法相当于标记清除算法执行之后,再进行一次内存碎片整理,差异就是移动式的回收算法

指针碰撞:如果内存空间规整且有序,即有用和未用的内存空间都在各自一边,那么只需要有一个记录着下次分配起始点的标记指针,当为新对象分配内存的时候,只需要通过修改指针的偏移量将新对象分配在第一个空闲的内存位置上。

在这里插入图片描述
5、垃圾回收相关概念
1、System.gc()的理解
在默认情况下,通过system.gc()或Runtime.getRuntime().gc()的调用,会显式触发Full GC()

2、内存溢出与内存泄漏
2.1、内存溢出(OOM):没有空闲内存,并且垃圾回收器也无法提供更多内存。
没有空闲内存的情况
(1)java虚拟机中的堆空间设置不够
(2)代码中创建了大量大对象,并且长期不能被垃圾回收器回收(存在被引用)

2.2、内存泄漏
含义:只有对象不会被程序用到,但是GC又不能把它们垃圾回收的情况,就叫做内存泄漏。
而实际情况下,一些不太好的实践会导致对象的生命周期过长甚至导致OOM,也可以叫做宽泛意义的内存泄漏。

举例
(1)单例模式:单例的生命周期和应用程序一样长,所以单例模式中,如果持有外部对象的引用的话,那么这个外部对象不能被回收,则会导致内存泄漏。
(2)一些提供close的资源未关闭导致内存泄漏,比如数据库连接,网络连接和io连接必须手动关闭,否则不能被回收。

6、JVM中的4种引用:强、软、弱、虚
(1)强引用:指程序中普遍存在的引用赋值,只要强引用还存在,宁可发生OOM报错,垃圾回收器就不会回收它。
(2)软引用:只要内存空间足够就不会回收它,如果内存空间不足,就会回收它。如果回收之后内存空间还不够,就会发生内存溢出。
(3)弱引用:被弱引用关联的对象只能存活到下一次垃圾回收之前,不管内存是否足够,都会被回收。
(4)虚引用:一个对象有虚引用的存在,对它的存活没有任何的影响,也无法通过一个虚引用来获得对象的实例,为一个对象设置虚引用的关联的作用就是,该对象被垃圾回收的时候会收到一个系统通知。

~软引用和弱引用非常适合保存那些可有可无的缓存数据。
~弱引用和软引用对象最大的不同就是:当GC在进行垃圾回收的情况,需要通过算法检查是否需要回收软引用对象,而对于弱引用对象,总是直接就行回收。弱引用对象更容易、更快被垃圾回收。
~虚引用必须使用一个引用队列,当垃圾回收器准备回收一个对象的时候,如果发现它有虚引用,就会在回收对象后,把这个虚引用加入到引用队列,以通知程序对象的回收情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值