JVM的垃圾回收机制

JVM的垃圾回收机制,第1张

JVM的垃圾回收机制

目录

jvm的基本组成

虚拟机的组成

运行流程

内存分配与回收策略

引用计数器算法:

可达性分析算法:

分代收集算法:

垃圾收集器:

Serial收集器

ParNew收集器

Parallel Scavenge收集器

Serial Old收集器

Parallel Old收集器


jvm的基本组成 虚拟机的组成

所谓java能实现跨平台,是因为在不同平台上运行不同的虚拟机决定的,因此java文件的执行不直接在 *** 作系统上执行,而是通过jvm虚拟机执行,我们可以从这张图看到,JVM并没有直接与硬件打交道,而是与 *** 作系统交互用以执行java程序

运行流程

内存分配与回收策略

判断对象已死的算法

在堆里面放着各种java对象,垃圾收集器在堆进行垃圾回收时,首要就是判断哪些对象还活着,哪些对象已经死去(即不被任何途径引用的对象)

引用计数器算法:

引用计数器算法简单概括为:给对象添加一个引用计数器,每当有一个地方引用该对象时,计数器+1,当引用失效时-1,任何时刻,当计数器为0的时候,该对象不在被引用.客观地说,引用计数器的实现简单,判定效率也高,大部分场景下是一个不错的选择,但是,当前主流的JVM均没有采用标记清除算法,原因在于,他很难决定对象之间相互循环调用的情况.

可达性分析算法:

在主流的商用程序语言中(如C#,JAVA)的主流实现中,都是通过可达性分析来判断对象是否存活,这个算法的思想就是通过一系列的成为"GC Roots"的对象来作为起始点,从这些节点开始向下搜索,搜索所走过的路径成为引用链,当一个对象到"GC Roots"没有任何引用链相连,则证明此对象是不可用的. 

如图所示,虽然Obj5,Obj6,Obj7互有关联,但是他们到GC Root没有任何连接链,所以判定为需要被回收的对象.常说的Gc Roots,特指的时垃圾收集器的对象,GC会手机那些不是GC Roots且没有被GC Roots引用的对象.

在Java中,可以作为GC Roots的对象包括下面几种:

1.虚拟机栈中引用的对象

2.方法区中类静态属性引用的对象

3.方法区中常量引用的对象

4.本地方法栈中JNI(即一般说的Native方法)的引用的对象

在JDK1.2之后对引用进行重新的扩充,分为强引用,软引用,弱引用,虚引用4种,这四种引用的强度依次递减

强引用:

强引用是在代码中普通存在的,类似于Object obj=new Object();只要强引用一直在,垃圾收集器就永远不会回收被引用的对象.

软引用:

软引用用来描述一些还有用单并非必须的对象,对于软引用关联着对象,当内存溢出异常发生之前,通过垃圾回收进行二次回收,如果二次回收完成之后,系统内存依然不够,才会抛出内存溢出异常,在jdk1.2以后用SoftReference类来实现软引用.

弱引用:

弱引用也是用来描述非必须对象的,但是它的强度相比于软引用来说更弱一点,它仅仅能生存到下一次垃圾回收之前,当垃圾收集时,无论内存是否走狗,弱引用对象都要被回收,在jdk1.2以后用WeakReference类来实现弱引用

虚引用:

虚引用是最弱的一种引用关系,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过一个虚引用来获取一个实例对象,为一个对象设置弱引用的唯一目的就是该对象在垃圾回收时受到一个系统通知,在jdk1.2以后用PhantomReference实现虚引用

分代收集算法:

当前商用的垃圾收集器采用的是分带垃圾回收,这种算法没有什么新的思想,知识根据对象的存货周期将内存分为几块,一般是java堆分为新生代和老年代,这样就可以根据各个代的对象特点选用最适当的回收算法,在新生代,每次垃圾回收都有大量的对象死去,只有少量存活,这样就是适合采用复制算法,只需要付出少量的对象复制成本就可以完成垃圾回收,而老年代因为存活率高,没有其他内存进行分配担保,就必须使用标记-整理进行回收.

1.分带分为年轻代和老年代.年轻代里分为Eden和Survivor区,通常默认的比例为8:1:1,每次只保留10%的空间用作预留区域,人后将90%的空间可以用作新生代对象.

2.每次一垃圾回收之后,存活的对象年龄对应+1,当经历15次还依然存活的对象,我们让它直接进入老年代.

3.另外一种进入老年代的方式是内存担保机制,也就是新生代的空间不够的时候,对象直接进入老年代

4.新生代的垃圾回收叫Minor GC ,老年代叫Full GC

垃圾收集器: Serial收集器

Serial收集器是最基本,发展最悠久的收集器,在JDK1.3之前是虚拟机新生代垃圾回收的唯一选择.这个收集器是一个单线程的,他的单线程的意义并不仅仅说明他只会使用一个CPU或者一条收集线程去完成收集工作,最重要的是,他进行垃圾收集时

ParNew收集器

ParNew收集器其实就是Serial收集器的多线程版本,除了使用多线程进行垃圾回收之外,其余可控参数,收集算法,停止工作线程,对象分配原则,回收策略等与Serial收集器完全一致.除了多线程实现垃圾收集之外,其他没有什么太多创新之处,但是他确实Server模式下的新生代的首选虚拟机收集器.其中一个重要的原因就是除了Serial收集器外,只有他能与CMS配合使用.在JDK1.5时期,HotSpot推出了一款在强交互应用跨时代的收集器CMS,这款收集器是HotSpot第一款真正意义上的并发收集器,第一次实现了垃圾回收与工作线程同时工作的可能性,换而言之,你可以边污染,边收集.

Parallel Scavenge收集器

parallel Scavenge收集器是一个新生代收集器,采用复制算法,有事并行的多线程垃圾收集器.他关注点与其他收集器关注点不一样,CMS等收集器的关注点在于缩短垃圾回收时用户线程停止时间,而Parallel Scavenge收集器则是达到一个可控制的吞吐量,所谓吞吐量就是CPU运行用户线程的时间与CPU运行总时间的比值,即 吞吐量=(用户线程工作时间)/(用户线程工作时间+垃圾回收时间),比如虚拟机总共运行100分钟,垃圾收集耗时1分钟,则吞吐量为99%,停顿时间越短越适合于用户交互的程序,良好的响应速度提高用户体验,但是高吞吐量则可以高效率的利用CPU的时间,尽快完成程序的运行任务,主要适合在后台运算而不需要太多交互的程序,有两个参数控制吞吐量量,分别为最大垃圾收集时间:-XX:MaxGCPauseMills,直接设置吞吐量大小:-XXGCTimeRatid

Serial Old收集器

Serial Old收集器是Serial收集器的老年代版本,他同样是一个单线程收集器,使用标记整理算法,这个收集的主要目的也是在给Client模式下使用,如果Server模式下,还有两种用途,一种是在jdk5以前版本中配合Parallel Scavenge收集器使用,另一种用途作为CMS的设备方案,在并发收集发生 Concurrent Mode Failure时使用.

Parallel Old收集器

Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和标记整理算法,这个收集器在jdk6中才开始使用的,在Parallel Scavenge收集器之一处于比较尴尬的阶段,原因是,如果新生代采用Parallel Scavenge收集,name老年代除了Serial Old之外,别无选择,由于老年代Serial在服务端的拖累,使得使用了Paralle Scavenge收集器也未必能达到吞吐量最大化的效果,由于单线程的老年代无法充分利用服务器多CPU的处理能力,在老年代很大而硬件比较高级的环境中,这种组合的吞吐量甚至不如Parallel Scavenge收集器+CMS知道Parallel Old收集器出现后,吞吐量优先收集其终于有了名副其实的组合,在注重吞吐量优先和CPU资源敏感的场合,可以采用Paralle Scavenge收集器+Parallel Old收集器

 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5703920.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存