垃圾回收(GC)是JVM的一大杀器,它使程序员能够更高效地专一于程序的开发设计,而不用过多地考虑对象的建立销毁等操做。可是这并非说程序员不须要了解GC。GC只是Java编程中一项自动化工具,任何一个工具都有它适用的范围,当超出它的范围的时候,可能它将不是那么自动,而是须要人工去了解与适应地适用。程序员
拥有必定工做年限的程序员,在工做期间确定会常常碰到像内存溢出、内存泄露、高并发的场景。这时候在应对这些问题或场景时,若是对GC不了解,极可能会成为我的的发展瓶颈。算法
接下来的两文将详细学习下JVM中垃圾回收(GC)的各个知识要点。本文先从GC的算法开始先了解,铺垫好基础,下一篇再详细讲JVM具体的GC实现。编程
垃圾回收,第一件事就是要搞清楚哪些东西是垃圾,然后才能对这些垃圾进行回收。微信
那么有什么办法识别对象是否为无用的垃圾呢?狭义地,怎么判断对象是否没被引用呢?并发
一般有如下两种算法去识别判断编程语言
引用计数算法
这个算法很是简单。给对象一个计数器,每当这个对象被引用了,计数器值加一;引用失效,则减一。但这个对象计数值为0的时候,证实是无用对象,能够被GC程序回收掉。这种算法比较普遍应用在一些脚本语言上,如FLASH、PYTHON等。
可是引用计数算法没法解决对象间相互引用的问题。当a对象引用了b对象,b对象也引用了a对象,这样a、b两个对象的计数器值都不会为0,即便这两个对象都被其余对象所引用,最终致使这些对象一直没法被回收。这种状况每每会出如今比较复杂的编程语言中。
高并发
可达性分析算法
可达性分析算法(GC roots算法),普遍应用于主流的商用语言。设置一个根节点,从图论角度来看,只要从该节点可达一个对象,证实这个对象是存活的(被引用)。
工具
一般地,GC会包含如下区域的对象:性能
了解完垃圾是怎么找出来后,接下来看看它们是怎么被清除的。如下介绍几种清除的算法。学习
标记-清除,顾名思义,先标记垃圾,再清除。它是GC最基础的算法,后续不少算法都是基于它上面去改进的。
标记的过程在上面搜索GC对象已经介绍过了。被标记的对象,在统一GC的时候会把标记的对象清除掉。这个算法比较简单,不作过多赘述。
这个算法有一个很明显的缺点,就是在垃圾回收后会产生大量不连续的碎片空间,致使程序要申请较大的对象时常没法找到合适的内存空间,迫使再次GC。
复制算法的存在,正是为了解决内存碎片问题。而且这个算法也是分代算法的基础。
将内存分为大小相等的两块,每次程序只使用其中一块,当GC发生的时候,把存活的对象复制到另一块内存中,整齐的排列,而后清空原来的那块内存。
能够看到,这种算法有点新生代转移到老年代的感受。
缺点:
这种缺点,在老年代中,对象存活率比较高的场景下是很是场景间。
针对复制算法的两个缺点,在老年代通常会用这种标记-整理算法。
把存活的对象移到内存的一段,而后把剩余的空间所有清空掉。
分代算法并非一个特定的算法,也没有什么新的内容。而是把内存分红多个区域,通常为新生代、老年代等。而后根据不一样区域不一样的特色,用不一样回收算法去回收垃圾。
例如新生代,对象存活率低,比较适用复制算法。老年代存活率高,比较适用Mark-Compact算法。
目前几乎全部的商业虚拟机都是采用分代收集的。具体不一样的收集器在下一文再详细说明。
更多技术文章、精彩干货,请关注
博客:zackku.com
微信公众号:Zack说码