记得以前去平安面试的时候,面试官问到了垃圾回收,我当时也就是说说了垃圾回收的原理,可是具体有哪些实现策略,我当时是懵的。面试
概念:算法
Java的垃圾回收机制是Java虚拟机提供的能力,用于在空闲时间以不定时的方式动态回收无任何引用的对象占据的内存空间。咱们用System.gc()或者
Runtime.getRuntime().gc() 来通知垃圾回收机(JVM)回收垃圾。不少人说垃圾回收回收的是没有用的对象,这里不许确的。并发
垃圾回收的做用:性能
1,按期发现那些对象再也不被引用,并把这些对象占据的堆空间释放出来。
优化
2,垃圾收集器还须要处理因为对象动态生成与销毁产生的堆碎块,以便更有效的利用虚拟机内存。spa
区分什么是垃圾(活动与垃圾的区分).net
引用计数法线程
堆中每个对象都有一个引用计数。当新建立一个对象,或者有变量被赋值为这个对象的引用,则这个对象的引用计数加1;当一个对象的引用超过生存期或者被设置一个新的值时,这个对象的引用计数减1。当对象的引用计数变为0时,就能够被看成垃圾收集。
这种方法的好处是垃圾收集较快,适用于实时环境。缺点是这种方法没法监测出循环引用。例如对象A引用对象B,对象B也引用对象A,则这两个对象可能没法被垃圾收集器收集。所以这种方法是垃圾收集的早期策略,如今不多使用。
对象
跟踪法blog
这种方法把每一个对象看做图中一个节点,对象之间的引用关系为图中各节点的邻接关系。垃圾收集器从一个或数个根结点遍历对象图,若是有些对象节点永远没法到达,则这个对象能够被看成垃圾回收。
容易发现,这种方法能够检测出循环引用,避免了引用计数法的缺点,较为经常使用。
经常使用的垃圾回收方法
标记-清除收集器
这种收集器首先遍历对象图并标记可到达的对象,而后扫描堆栈以寻找未标记对象并释放它们的内存。这种收集器通常使用单线程工做并中止其余操做。
标记-压缩收集器
有时也叫标记-清除-压缩收集器,与标记-清除收集器有相同的标记阶段。在第二阶段,则把标记对象复制到堆栈的新域中以便压缩堆栈。这种收集器也中止其余操做。
复制收集器
这种收集器将堆栈分为两个域,常称为半空间。每次仅使用一半的空间,虚拟机生成的新对象则放在另外一半空间中。垃圾回收器运行时,它把可到达对象复制到另外一半空间,没有被复制的的对象都是不可达对象,能够被回收。这种方法适用于短生存期的对象,持续复制长生存期的对象因为屡次拷贝,致使效率下降。缺点是只有一半的虚拟机空间获得使用。
增量收集器
增量收集器把堆栈分为多个域,每次仅从一个域收集垃圾。这会形成较小的应用程序中断。
分代收集器
这种收集器把堆栈分为两个或多个域,用以存放不一样寿命的对象。虚拟机生成的新对象通常放在其中的某个域中。过一段时间,继续存在的对象将得到使用期并转入更长寿命的域中。分代收集器对不一样的域使用不一样的算法以优化性能。这样能够减小复制对象的时间。
并发收集器
并发收集器与应用程序同时运行。这些收集器在某点上(好比压缩时)通常都不得不中止其余操做以完成特定的任务,可是由于其余应用程序可进行其余的后台操做,因此中断其余处理的实际时间大大下降。
并行收集器
并发收集器与应用程序同时运行。这些收集器在某点上(好比压缩时)通常都不得不中止其余操做以完成特定的任务,可是由于其余应用程序可进行其余的后台操做,因此中断其余处理的实际时间大大下降。
自适应收集器
根据程序运行情况以及堆的使用情况,自动选一种合适的垃圾回收算法。这样能够不局限与一种垃圾回收算法。
这里要说到一个垃圾算法上的实现,火车算法
垃圾收集算法一个很大的缺点就是难以控制垃圾回收所占用的CPU时间,以及什么时候须要进行垃圾回收。火车算法是分代收集器所用的算法,目的是在成熟对象空间中提供限定时间的渐进收集。目前应用于SUN公司的Hotspot虚拟机上。
在火车算法中,内存被分为块,多个块组成一个集合。为了形象化,一节车箱表明一个块,一列火车表明一个集合,见图一
图一
注意每一个车箱大小相等,但每一个火车包含的车箱数不必定相等。垃圾收集以车箱为单位,收集顺序依次为1.1,1.2,1.3,1.4,2.1,2.2,2.3,3.1,3.2,3.3。这个顺序也是块被建立的前后顺序。
垃圾收集器先从块1.1开始扫描直到1.4,若是火车1四个块中的全部对象没有被火车2和火车3的对象引用,而只有火车1内部的对象相互引用,则整个火车1都是垃圾,能够被回收。
如图二,车箱1.1中有对象A和对象B,1.3中有对象C,1.4中有对象D,车箱2.2中有对象E,车箱3.3中有对象F。在火车1中,对象C引用对象A,对象B引用对象D,可见,火车2和火车3没有引用火车1的对象,则整个火车1都是垃圾。
图二
若是火车1中有对象被其它火车引用,见图三,扫描车箱1.1时发现对象A被火车2中的E引用,则将对象A从车箱1.1转移到车箱2.2,而后扫描A引用的对象D,把D也转移到车箱2.2,而后扫描D,看D是否引用其它对象,若是引用了其它对象则也要转移,依次类推。扫描完火车1的全部对象后,剩下的没有转移的对象都是垃圾,能够把整个火车1都做为垃圾回收。注意若是在转移时,若是车箱2.2空间满了,则要在火车2末尾开辟新的车箱2.4,将新转移的对象都放到2.4,即火车的尾部)
图三
补充说明:垃圾回收器一次只扫描一个车箱。图三中的对象B与C并非当即被回收,而是先会被转移到火车1的尾部车箱。即扫描完1.1后,B被转移到火车1尾部,扫描完1.3后,C被转移到车尾。等垃圾收集器扫描到火车1尾部时,若是仍然没有外部对象引用它们,则B和C会被收集。
火车算法最大的好处是它能够保证大的循环结构能够被彻底收集,由于成为垃圾的循环结构中的对象,不管多大,都会被移入同一列火车,最终一块儿被收集。还有一个好处是这种算法在大多数状况下能够保证一次垃圾收集所耗时间在必定限度以内,由于一次垃圾回收只收集一个车箱,而车箱的大小是有限度的。
本文同步分享在 博客“xiangzhihong8”(CSDN)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。