栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

JVM垃圾回收及常见垃圾回收器回顾

JVM垃圾回收及常见垃圾回收器回顾

JVM垃圾回收:

jvm垃圾回收机制: Java语言无需开发人员手动参与内存的分配与回收,得益于垃圾回收机制,自动内存管理机制,使得程序员更加专注于业务代码的开发

存在的问题:在实习编程过程中,会遇到OOM,要排查并解决问题,我们要真正了解jvm是如何管理对象。

回收区域
对于年轻代,老年代,全堆和方法区

从回收频率上讲:年轻代>老年代>方法区

垃圾回收相关算法
垃圾回收分为两个阶段:垃圾标记阶段,垃圾回收阶段

垃圾标记阶段:垃圾回收前要判断哪些对象为垃圾对象,才能之后进行回收

对象存活的判断:这里一般有两种算法
1.引用计数法: 每有一个引用指向该对象,则引用计数器会+1,当引用失效时引用计数器-1,当引用计数器为0时,表示该对象不再使用,被认为是垃圾。

优点: 实现简单,垃圾对象便于识别;判定效率高,回收没有延迟性

缺点:

需要单独的字段存储计数器,增加了存储空间的开销。
每次随着加法与减法的操作,无疑增加了时间的开销。
**最严重的问题时无法解决循环依赖的问题,导致在垃圾回收器中很少使用该算法。

public class TestGC{
     object reference=null;
     public static void main(String[] args){
     TestGC obj1=new TestGC();
     TestGC obj2=new TestGC();

	  //循环依赖
	  obj1.reference=obj2;
	  obj2.reference=obj1;
		
	  obj1=null;
	  obj2=null;

	   //执行垃圾回收
	   System.gc();
     }
}

在上述代码中虽然最后将两个引用都置为null,即引用指向两个对象,本该引用计数器都应为0,标记为垃圾.但是由于代码中的循环依赖,两个对象的reference引用还在只想两个方法,则他们的引用计数器会大于0,导致不能被回收,严重的情况下可能会发生OOM。

2.可达性分析算法 (跟搜索算法,追踪性垃圾收集算法):以根对象集合(GC Roots)为起始点,从上至下的搜索方式搜索被根对象连接的目标对象是否可达。 在可达性分析算法后,存活的对象直接或间接的于根对象相关联,如果一个对象不与根对象相连,则会被标记为垃圾进行回收。只有跟根对象直接或间接相连的对象才是存活的对象。

哪些对象能够成为GC Roots对象?
1.虚拟机栈中引用的对象
2.方法区中类静态属性所引用的对象
3.方法区中类静态属性引用的对象
除了一些固定的集合以外,根据所选择的垃圾回收器及内存区域的不同,还可以会有一些其他的对象加入

垃圾回收阶段:当确定哪些对象垃圾对象之后,接下来就会进行垃圾回收,释放掉内存中的空间,以便为新的对象分配内存。

常用垃圾回收算法:1.标记-清除算法 2.复制算法 3.标记压缩算法 4.分代手机算法 5.增量手机算法 6.分区算法

标记清除算法:
执行过程:

  • 标记:从根对象开始遍历,标记所有被引用的对象,一般在对象的Healder中记录为可达对象
  • 清除:重新从根对象进行便利,如果发现对象中的Headler中没有被标记为可达对象,将其回收。

缺点:

  • 效率不高
  • 在进行GC时,需要停止整个应用程序。
  • 清理出来的内存空间是不连续的,产生内存碎片

复制算法

核心思想:将内存空间分为两个部分from区和to区,每次只使用其中一块(from区),将活着的对象复制到没有使用的内存块中(to区),之后清除正在使用的内存块(from区)中所有的对象。之后from区变为to区,to区变为from区,转移内存的方向总是从from区到to区。

优点:

  • 无标记和清除阶段,运行高效
  • 保证了空间的连续性,不会出现内存碎片。

缺点:

  • 需要2倍的内存空间。

应用场景:在要回收的对象很多,存活的对象很少,需要转移的存活对象也比较少。新生代中经常发生。

标记-压缩算法
复制算法在存活对象少,垃圾对象多的时候适用,比如在年轻代,但是在老年代中存活对象多,垃圾对象少,不适合用复制算法。因而出现了标记压缩算法

执行过程:
第一阶段和标记清除算法一样,从根对象向下寻找所有存活对象。
第二阶段将存活的对象移动压缩的内存的一端,之后清理边界外的区域。

与标记清除算法相比,相当于标记清除后将存活的对象移动到一边,这样会减少内存碎片的产生

指针碰撞:经过标记-压缩算法后,内存区域被严格的分为存活区与非存活区。临界点创建一个指针,如果要分配对象,将指针往非存活区的方向移动一个对象的距离,这种分配方式就是所谓的指针碰撞。

优点:

  • 不会产生内存碎片
  • 与复制算法相比,充分利用了内存的空间

缺点:

  • 效率比标记整理算法要低一些
  • 移动对象,还用将引用的地址告知引用,修改引用地址
  • 移动过程中,要全程停止应用程序

分代算法
核心思想:分代指的是区分不懂的内存区域(年轻代Young Gen,老年代Tenured Gen).上面的三个算法都有明显的优缺点。衍生出了分代算法。即不同区域采取不同的回收算法。

在Java运行时 ,会产生大量的对象,有大量的对象与业务相关,如session对象,线程,socket连接对象等等,这些都是生命周期比较大的对象。还有一些对象时临时的变量,这些对象寿命周期都非常短,比如String类型的变量。

目前绝大部分的GC 都使用分代算法。

年轻代:复制算法的速度是最快的
老年代:该区域存在大量存活率高的对象,一般由标记-清除算法与标记-整理算法混合使用。

增量收集算法
上诉的算法,在垃圾回收的过程中应用程序会停止,俗称Stop The Word状体,该状态下所有的线程将会暂停工作,等待垃圾回收完成。为了解决问题,于是产生了增量收集算法。

核心思想:如果一次性进行垃圾回收,会造成长时间的应用程序的停止,那么让垃圾回收线程与应用程序线程交替执行,每次垃圾回收只回收一小部分的区域,接着替换到应用程序线程,反复交替,知道垃圾收集完成。

增量算法其实本质上还是基于传统的标记-清除算法,标记-整理算法,复制算法,知识每次处理的内存区域变小,不回让应用程序停止很长的时间。

缺点:虽然在运行过程中,停顿的感觉变少。但是线程切换与上下文转换的发生造成成本的上升。

分区算法

正常情况下,一个GC区域越大, GC执行时长越久,应用程序停顿的时长变久,为了更好的减少停顿的时长,将一个内存区域分成多个小块,根据停顿时间,合理的回收部分小块,而不是整个堆空间。

这种算法的好处是可以控制一次挥手多少个小的内存区域。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/281548.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号