JVM学习(三)垃圾回收
前言
侵删,记录自己学习时看到的一些片段
GC(垃圾回收)
通过一系列措施释放垃圾占用的内存空间,防止内存泄漏
垃圾判断算法
引用计数算法
这是一种实现简单,判定效率高的算法。
实现方法:给对象添加一个引用计数器,每当有一个地方引用它时,计数器+1,当引用失效时,计数器-1。当对象的计数器为0,此时判定此对象不可能再被使用。
算法缺陷
无法解决循环引用问题。当对象a和对象b相互引用对方,并且两对象再无任何引用时,引用计数算法无法通知GC系统回收对象a和对象b。
可达性分析
为了解决引用计数法的循环引用问题,Java使用了可达性分析方法。
算法思路:通过一系列的称为“GC Roots”的对象作为起始点,从这些节点向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象不可用。
不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经过两次标记过程。两次标记后仍然是可回收对象,则面临回收
垃圾回收算法
标记清除算法
最基础的垃圾回收算法。分为两个阶段,标记和清除。
标记阶段:标记出所有需要回收的对象
清除阶段:回收被标记的对象所占用的空间
算法缺陷
内存碎片化严重,容易造成后续实例化大对象时无法找到可利用空间
复制算法
为了解决标记清除算法内存碎片化问题而被提出的算法。按内存容量划分为等大小的两块。每次只使用其中一块,当一块内存满后将仍然存活的对象复制到另一块上,后将已使用的内存清除
算法缺陷
在空间上造成浪费,可用内存只有总内存的一半。当存活对象增多之后,算法效率会大大降低。
标记整理算法
结合标记清除算法和复制算法而提出。标记阶段和标记清除算法相同,不同在于标记后不是回收对象所占用的内存,而是将存活的对象移向内存的一端,然后清除端边界外的对象。
算法缺陷
虽说解决了内存碎片问题,同时也规避复制算法只能利用一半内存的弊端,但标记整理算法内存变动更加频繁,需要整理所有存活对象的引用地址,效率比复制算法差很多。
分代收集算法
分代收集算法是目前大部分JVM所采用的方法,核心思想是根据对象存活的不同生命周期将内存划分为不同区域,一般划分为新生代和老年代。
对新生代而言,大部分JVM的GC对新生代都采用复制算法,但并不会按照原复制算法1:1划分空间,而是将新生代空间划分为eden区(较大),from survivor区(较小)和to survivor区(较小),每次仅使用eden区和其中一块survivor区。回收时,将该两块空间存活对象复制到另一块survivor区。
对老年代而言,由于老年代每次只回收少量对象,对象存活率高,因此采用标记整理算法或标记清除算法
新生代与老年代
- 当新生代发生了一次GC,eden区和from survivor区往to survivor区复制对象内存不足时,则会将这个对象存储到老年代。
- 当一个对象实例化所需内存过大时,会直接移入老年代存储。
- 当对象在survivor区存活一次后,年龄+1。默认情况下年龄达到15会被移到老年代中。
参考资料
《Java虚拟机(第二版)》
《JAVA核心面试知识整理.pdf》