Java虚拟机-垃圾收集器

垃圾回收理论

引言:
我们已经知道jvm管理的运行时数据内存大致分为:程序计数器、方法区、虚拟机栈、本地方方法栈、堆。其中的程序计数器、虚拟机栈、本地方法栈与线程同生同灭,当一个执行之后,虚拟机栈产生一个栈帧,程序计数器开始记录字节码执行位置,这些都是线程私有的。他们的内存管理,随着线程的创建而分配,随着线程的销毁而释放。
而作为共享区的方法区和堆,是大量实例化候对象,以及记录类信息的相关内存区域。由于实例话对象只有在运行时才知道创建的对象个数,所以这部分内存的分配、回收也是动态的。而方法区类的回收也需要算法进行判断。


1.概述

通常垃圾收集被认为是java发展的产物,但其实1960就有人研究过关于垃圾收集问题,大致可以分为三个部分

  • 哪些内存需要回收
  • 什么时候收集
  • 怎么回收

2.那些内存需要回收

哪些内存需要回收?当然是不在需要的对象需要回收。那么,如何判断一个对象不再需要呢?

2.1引用计数法

简单说就是在对象中记录该对象当前被引用的次数,被引用一次就加一,反之减一。引用计数法在java虚拟机判断对象存活中很少使用,缺陷之一就是无法解决对象之间循环引用的问题。

2.2可达性分析

可达性分析是大多数虚拟机采用的方法。所有从GC Root出发不能到达的对象,判定为已死对象,需要回收。


可达性分析
很多对象都可以成为GCRoot,比如,同步锁是有的对象、静态变量、局部变量、参数等等。

2.3已死对象就一定会被回收?

被判定为已死的对象也不会立即被回收,真正被回收至少需要两次标记过程,可达性分析判定不可达时标记一次,随后进行筛选,如果对象没有重写finalize()方法或已经被虚拟机执行过finalize()方法,那么该对象才真正宣告死亡。
所以说finalize()方法中,不可达对象依然可以获救。
如果说,在finalize方法中,对象被其他GC Root对象引用,那么就不会被清除

2.4方法区能不能回收

虽然说堆中进行垃圾回收的效益很客观,大概能回收70%~99%的内存,而方法去进行垃圾回收往往回收条件苛刻,而且效果不大。但是对于大量使用类加载器的框架,方法区需要得到重视。
方法区的回收对象主要是,常量池中废弃的常量、不再使用的类。

3.垃圾回收算法

分代理论:垃圾回收算法主要有以下三个理论支持,也是大量实验研究的结果经验
弱分代理论:大部分对象都是朝生夕死。
强分代理论:熬过垃圾回收的次数越多的对象越难回收。
跨代回收理论:对象关联大部分只发生在同代之间。
由此,使用分代理论的jvm把堆至少分为新生代和老年代两个部分。

垃圾回收算法,主要分为:标记-清除法,标记-整理法,标记-复制法。

3.1标记清除法

顾名思义,就是对不可达的对象/可达对象进行标记,随后清除/保留。
但是方法由于清理对象的随机性,会产生或大或小的内存间隙,无法获取到足够的连续内存

3.2标记复制法

1989年,针对新生代朝生夕死的特点,Andrew Appel提出了半代复制的优化,把内存划分为占80%的Eden和两块10%的Survivor。每次收集时,只使用一块大的和一块小的,并把存活的对象复制到另一块小的当中。

针对存活对象占比多于10%,也就是小的Survivor存不下的情况,Aplel也有响应的逃生门,也就是将多余的存活对象分配到堆中。

3.3标记整理法

针对老年代大多数存活的特点,标记整理法先对已死对象进行标记,然后任然存活的对象进行移动,移动到一侧。然后将边界之外的内存进行清空。
可以说标记整理发和标记清除法的前半部分是一样的,但是标记真理在后半部分会进行移动。如图
标记整理法
大量的移动存活对象也是巨大的消耗,而且在移动过程中需要更新其他引用。
但是如果不移动,就会产生内存碎片化问题,需要依靠内存分配器和访问器来解决。内存访问是用户最频繁的操作,这样对本就负担过重内存操作加重。
基于以上,不同考虑的收集器会使用不同的算法。CMS收集器就是基于标记清除算法的,而Parallel Scavenge收集器就是基于标记整理法的。
另外,作者还提到了一种混合式的方法,就是在碎片化程度低的时候,使用标记清除法,而在碎片化程度不能忍受的时候使用标记整理法。

几款经典的垃圾收集器

垃圾收集器
上图展示了常见的垃圾收集器以及他们所作用的分代,下面将介绍这几款垃圾收集器。

1.serial收集器

最古老的垃圾收集器,只使用单线程进行垃圾收集,收集采用的是标记-复制算法。收集过程中需要暂停所有用户线程,停顿时间大概在几十到二百毫秒不等。

2.parNew收集器

serial收集器的并行版本,使用多线程进行垃圾回收,其他的与servial基本一致

3.CMS收集器

并发低停顿收集器,第一款可以与用户线程几乎并发执行的收集器。
上面所说的垃圾收集器,无一例外需要在收集过程中停止用户的线程。而CMS的停顿时间极短,几乎可以忽略。
CMS手机的过程为:

  • 初始标记 ,标记出GC Root直接关联对象,速度很快
  • 并发标记 ,从直接关联对象出发多线程遍历对象图
  • 再标记 ,标记并发标记过程中,由于用户线程还在运行产生的新的垃圾
  • 并发清除 ,并发清除垃圾

CMS收集器采用标记清除算法,以最小化停顿时间为目的。他的低延迟性,对于以响应速度为最求目标的B/S类型网站来说是很有帮助的。

4.Parallel Scavenge收集器

一款以实现可控吞吐量为目的的收集器。也就是说,他不在乎一次垃圾收集停顿时间的快慢,也不会一次性对新生代进行回收。在用户设置了期望的吞吐量之后,他会控制垃圾收集的时间与次数。
吞吐量:运行代码时间/(运行代码时间+垃圾收集时间)

5.G1收集器

G1垃圾收集器推推出的期望是替代掉JDK5推出的CMS收集器。他是第一款全功能的,可以对全堆进行回收的收集器。开创了region内存布局以及局部回收的思想。
G1不像前几款收集器那样把堆内存划片,一边是新生代,一边是老年代。G1收集器把整个内存化成一块一块的小region,每个小的内存区域既可以是新生代也可以是老年代,所以他也没有抛弃分代理论的理论。
在收集时,建立了以衰减平均值为指标的可预测停顿回收模型。在以满足用户设置的期望停顿时间为前提下,选择能会的最大收益的region内存进行回收。region之间采用的是标记复制算法。从整个内存来看,采用的是标记整理法。
由于维护很多收集表,小的region也要维护收集表,同时由于G1收集器的复杂性,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值