0
点赞
收藏
分享

微信扫一扫

JAVA虚拟机下篇 之 JVM的垃圾回收机制和算法 以及JAVA中的引用

是她丫 2022-03-15 阅读 33

什么是GC(垃圾回收机制)

在系统运行过程中,会产生一些无用的对象,这些对象一直占着内存,如果不对这些对象进行清除,会导致内存资源耗尽. 所以就需要GC垃圾回收机制 回收 堆 和 方法区的内存

怎么判断垃圾对象

JVM采用引用计数法和可达性分析法判断一个对象是否需要被回收

引用计数法

每个对象创建的时候,给对象绑定一个计数器,每当一个引用指向这个对象的时候,计数器加一;每当有一个指向改对象的引用被删除时,计数器减一.这样当没有引用指向改对象时,计数器为0,表示这个对象是垃圾了,可以被回收了

优点 : 实现简单,判断效率高

缺点: 不能解决循环依赖问题,所以一般不用

对象A 引用了对象 B 对象B 引用了对象A 那么这两个对象将永远存活

可达性分析法(主流虚拟机采用)

从GC ROOTS 开心向下搜索,搜索走过的路径为引用链,当一个对象到GC ROOTS 没有任何引用链时,则表示该对象不可用,表示可以被回收

优点: 能解决循环依赖问题

和引用计数比,没有缺点

三种垃圾回收机制

Minor GC

发生在新生代的垃圾回收,最频繁,速度也最快

当eden区满时,触发Minor GC .当为一个对象申请内存地址时,发现eben区内存不够用就发生Minor GC

Major GC

发生在老年代的垃圾回收,通常会伴随着Minor GC ,Major GC通常伴随着 Minor GC 速度比 Minor GC慢

有五种情况会导致Major GC

  1. 晋升到老年代的对象大于老年代剩余的空间内存
  2. 永久代空间不足
  3. 手动执行了System.gc()方法
  4. Minor GC之后存活的对象超过了老年代的空间
  5. 方法区空间不足(1.8之前)

Full GC

同等于Major GC

Major GC 与 Full GC都会导致 STW ( stop the world ) ----> 整个世界都停了 所以应该极力避免 Full GC

堆中新对象申请内存的过程图

JVM 堆中新对象申请内存过程

四种垃圾回收算法

复制算法(用于新生代)

将内存平均分为两份,每次只使用其中一部分,当这部分内存满的时候,将其中存活的内存复制到另一半内存空间,然后将这部分内存清空,再去使用另一半内存空间.循环下去

两个幸存者区永远只会使用其中的一个 另外一个永远是空的 from 和 to 相互转换

复制算法与标记整理算法的区别在于 该算法不是在同一个区域复制,而是将所有存活的对象复制到另一个内存区域内

优点:

在存活对象不多的情况下,性能高,能解决内存碎片和java垃圾回收算法之-标记清除 中导致的引用更新问题。

缺点 :

会造成一部分的内存浪费。不过可以根据实际情况,将内存块大小比例适当调整;如果存活对象的数量比较大,复制算法的性能会变得很差

标记清除算法(用于老年代)

创建一个对象的时候存储一个标记位,记录状态是死是活

优点

可以解决相互循环引用问题,必要时才进行回收

缺点

标记和清除效率不高,回收时应用需要挂起,.且会造成内存碎片问题

内存碎片 : 内存中的存储空间不连续,当需要申请连续的存储空间时无法申请到

标记整理算法(用于老年代)

创建对象的时候储存一个标记位,记录对象的状态(是死是活),但一阶段不进行对象删除,还要进行二阶段,在二阶段将存活的对象整理起来,放到另一端空间,然后再把剩下的对象全部清除

优点

解决了标记-清除算法造成的内存碎片问题

缺点

由于在二阶段移动了对象,所以需要去更新引用

分代算法(JVM采用)

这种算法,根据对象的存活周期的不同将内存划分成几块,新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。可以用抓重点的思路来理解这个算法。

新生代对象朝生夕死,对象数量多,只要重点扫描这个区域,那么就可以大大提高垃圾收集的效率。另外老年代对象存储久,无需经常扫描老年代,避免扫描导致的开销。

在新生代,每次垃圾收集器都发现有大批对象死去,只有少量存活,采用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。

而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须“标记清除法或者标记整理算法进行回收

垃圾收集器介绍

image-20220315233213510

JAVA中的引用

强引用

最普遍的引用方式,当内存不足时,JVM宁愿抛出OOM异常,也不会回收强引用的对象

软引用

有用但是不是必须的对象,当JVM内存不足时会回收该对象,在Java中用java.lang.ref.SoftReference类来表示

在实际程序设计中一般很少使用弱引用与虚引用,使用软引用的情况较多,这是因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生

怎么利用软引用解决内存不足

利用软引用和弱引用解决OOM问题:假如有一个应用需要读取大量的本地图片,如果每次读取图片都从硬盘读取,则会严重影响性能,但是如果全部加载到内存当中,又有可能造成内存溢出,此时使用软引用可以解决这个问题。

设计思路是:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。

弱引用

只要发生GC就会被回收的对象

在java中,用java.lang.ref.WeakReference类来表示 像我们熟系的线程变量类 ThreadLocal中的ThreadLocalMap就是继承了WeakReference

image-20220315233526758

虚引用

如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收的活动

在java中用java.lang.ref.PhantomReference类表示

举报

相关推荐

0 条评论