标签:null details 获取 单线程 log com 老年 art parallel
总览
本文会介绍垃圾回收的以下几个方面。
在开始讲垃圾回收之前,先通过一张图快速回忆一下运行时内存
为什么需要垃圾回收
从哪里回收
如何判断一个对象需要回收呢?
这种算法缺点是当两个对象互相引用的时候,就不会被回收。
上图就是一个可达性分析的常见场景,对象三什么时候回被回收?先上结果:对象三是软可达,正常情况下在内存不足的时候会被回收。
这里需要理解两个概念
为了更加灵活的控制对象的生命周期,将对象引用分为四个级别。
Object o=new Object();
SoftReference<String> sr = new SoftReference<String>(new String("hello")); System.out.println(sr.get());
Object obj = new Object(); WeakReference<Object> WeakRef =new WeakReference(obj); Object objg = WeakRef.get();
ReferenceQueue<String> queue = new ReferenceQueue<String>(); PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue); System.out.println(pr.get());
理解了上面两个概念之后,我们在思考下面一个问题,如果一个对象的引用有多个,怎么通过可达性决定回收周期呢?
有两个原则。
上图中对象三是一个软可达对象,因为左半边的链最弱的是弱引用,右边的链最弱的是软引用,左右两边最强的是软引用。
知道了有对象需要回收之后,我们怎么回收呢?有三种方法
先需要回收的对象做标记,之后扫描,将有标记的回收。这种算法效率不高,会产生碎片。最终导致大对象分配空间时无法找到足够大的内存而频繁触发垃圾回收。
为了解决标记-清除算法碎片的缺点,提出了复制算法,将内存容量按照大小分成两份,每次使用其中的一半,当内存耗尽之后将存活对象有序的复制到另一半中,并清理当前内存。
这种算法也有缺点:浪费一般空间;效率也跟存活对象多少有关,存活对象多算法效率会将大大降低。
为了解决复制算法浪费空间的缺点,并利用标记清理的优点,提出了这个算法,就是先标记回收对象,完了之后会将存活对象向同一端移动,然后清理需要回收的对象,这样就保证了空间的连续性。
从回收对象生命周期不同的角度讲内存划分为不同的区域:新生代和老年代,并结合了前面的复制算法和标记整理算法。
新生代中存放的是:新生成的对象实例,也是垃圾回收对象最多的区域,用到的是复制算法。
老年代会存放的是:在新生代中经历过多次垃圾回收仍然存在的对象;另外新生代生成大对象空间不够时也会在老年代中分配。这里采用的是标记整理算法对老年代区域进行清理。
其中,新生代又细分为三个区:Eden去,From Survivor区,To Survivor区,比例是8:1:1。
每次会使用Eden和一块Survivor区(90%新生代内存)服务对象,在触发回收机制时会采用复制算法,将两块区中存活的对象复制到另外10%的内存中,然后清理待回收对象。
这里考虑一个有趣的问题,如果老年代的对象有引用到新生代的,这种情况怎么处理的呢?用的是写屏障,会将这种类型的所有引用都放到一个集合中,标记时需要处理这个集合。
HotSpot JVM基于上面的垃圾回收算法实现的垃圾收集器有哪几种呢?
参考资料:
https://blog.csdn.net/zhangerqing/article/details/8214365
https://blog.csdn.net/wxfx888/article/details/78074145
标签:null details 获取 单线程 log com 老年 art parallel
原文地址:https://www.cnblogs.com/darrenqiao/p/9206554.html