JAVA中垃圾处理,垃圾处理算法

来源:互联网 发布:大数据可视化 网络攻击 编辑:程序博客网 时间:2024/05/20 02:55

前言


面试中经常面试官会问道,对垃圾算法有了解吗,通常笔者就会感到很不解,真是应了那句话”面试造飞机,工作拧螺丝的比喻“。其实我们写代码中,对垃圾算法的了解多少,影响不到多少。但,换句话说,想要写出高质量的代码,对垃圾的算法了解还是有必要的。

内存模型

jvm的内存主要分为堆和栈,栈内存用于存储线程的上下文信息,如方法参数,局部变量等。堆则是存储对象的内存空间,对象的创建和释放,垃圾回收就在这里进行。
分代垃圾回收:
JVM的堆分为年轻代和老年代,又将年轻代分为,Eden区(Eden Space),From区和To区,新建的对象总是在Eden区,当Eden区满了,触发一次Gc,将未被使用的对象,复制到From区,当Eden区满时,再次触发一次Gc,又将未被使用的对象复制到从Eden、From区到To区。当再次触发一次Gc时,又将Eden、To区的对象复制到From区。某些对象会在From区,和To区来回复制。
当某些对象,经过多次复制还没有被回收,超过规定阀值这些对象就会被复制到老年区(Old Generation)。

当老年区也被用完,会触发Full Gc全量回收。这样对系统性能有较大影响。

这里写图片描述

Gc算法

对象的生与死

要想回收对象,首先判断对象是否还存活

引用计数法:
简单的来说引用计数法,就是给每个对象一个引用计数器,当有一个地方引用时,计数器加1,引用失效时,计数器减1。当引用计数器为0时,判定这个对象不会被使用。
但是主流的java虚拟机都不会采用。因为应用计数法存在一个问题相互循环引用的问题。
例如:A对象引用B,B对象引用A,但是A、B对象都不会被使用。

可达性分析计算:
这个算法的思路就是,通过一系列成为Gc Roots的对象作为起始点,从这些节点开始向下搜索,所走过的路径称为应用链。当一个对象到GcRoots没有任何引用链时,则证明该对象不再使用。

可作为Gc Roots的对象包括下面几种:
栈中引用的对象
方法区中静态属性引用的对象,常量引用的对象。
本地方法栈中JNI,引用的对象

垃圾回收算法

分为:标记清除、复制算法、标记整理

标记清除
当判断对象没有引用,且应该回收之后。进行对象的回收。比较基础的算法。
该算法存在的问题:产生内存碎片、清除效率不高。

复制算法
为了解决效率和内存碎片问题,复制算法出现了,简单的来说就是把存活的对象复制到内存的一块上,一次性清除回收对象。

标记-整理
解决复制算法的内存,需要额外的担保的问题。当内存中存活的对象过多时,复制算法的效率就很低了。例如老年代对象。

标记清整理算法,基于标记清除,不同的是,标记清除,直接对对象进行清除操作。标记整理,让所有存活对象向一端移动,然后直接清除,边界以外的内存即可。

分代收集算法
顾名思义,对年轻代和老年代的对象,分别采用的不同的算法,实现回收,例如年轻代存活对象较少,就可以采用复制算法。老年代存活对象较多,就可以采用标记整理算法。

总结,垃圾回收算法不仅仅是笔者这样写的这么简单,当然不同虚拟机或者自己开发的虚拟机。都会有自己的一套算法。只要能保证高效、安全的回收内存,都是可以相互学习的。