垃圾收集器

2019-04-10  本文已影响0人  chengcongyue

引言

垃圾收集(简称GC),在产生是,就需要考虑一下三个方法:

1判断对象是否已死

1.1 引用计数法

大概就是为每一个对象添加引用计数器,当有一个地方引用它时,我们就为计数器加1,当引用失效时,就为计数器减1.
但是,引用计数法无法解决对象的循环引用问题

obj1.instance=obj2
obj2.instance=obj1
//然后obj1,obj2置空
obj1=null;
obj2=null;
System.gc()

结果虚拟机没有因为他们相互引用就不回收他们(他们被回收了),说明java虚拟机并没有使用引用计数法

1.2 根搜索算法

现在主流的商用语言中,大部分都使用了根搜索算法,这时候我们就要引出"GC ROOT"了,我们以GC ROOT为起始点,依次向下搜索,走过了路径称作是引用链,当一个对象到达GC ROOT是不可达的时候,证明此对象是不可用的


图片.png

GC ROOT回收的对象包括如下几种:

1.3 引用

在JDK 1.2 之前,我们把引用称作是一个数据,里面存储的数据,是另一块内存的起始地址,这个就叫做引用,过于狭隘
在JDK 1.2 之后,强引用 软引用 弱引用 虚引用

1.4 对象的自我拯救

在这一节开始之前,我们要先明确两点

protected void finalize() throws Exception
{
    super.finalize();
    对象=this;//这个时候就实现了自我拯救
}

finalize()能够做的所有工作,都可以用其他的方式实现,并且可以做的更好,更及时

2 垃圾回收算法

2.1 标记-清除算法

根据题目就可以知道这个算法包括两部分内存,即标记和清除两部分,这种回收方式的缺点较多,标记和清除的效率都不是很高,空间问题,在回收一部分之后,产生大量的不连续的内存碎片.太多的内存碎片会导致无法找到足够的连续内存而不得不触发另一次垃圾回收动作


标记清除算法

2.2 复制算法

将内存划分为同样大的两块,每次只是用其中的一块,当一块的内存使用完了,我们将存活的对象复制到另一块上去,然后再把已使用的内存空间清理掉.但是这种操作会导致内存缩小为原来的一般

图片.png
进一步优化,将内存区域划分成一块较大的Eden区域和两块较小的Survivor区域,每次执行标记清除算法,只是用其中的Eden区域和一块Survivor区域.当回收时,我们将存活的对象拷贝到另一块没有使用的Survivor区域上去,Eden和Survivor区域的分配比例是8:1:1,所有每次只有10%会被浪费.
但是就会有一个问题,如果经过一次GC存活的对象超过了10%,我们该怎么办,这个时候,我们就需要依靠老年代进行分配担保,分配担保机制会导致会使得对象直接进入老年代

2.3 标记-整理算法

针对于老年代的算法,不是整体的复制,而是将存活的对象向一边移动,然后清理掉边界以外的内存


图片.png

2.4 分代算法

将堆这个区域分为新生代和老年代,然后根据每个年代的特点采用最适合的收集算法.
对于新生代来说,每次垃圾回收都会有大量的对象死去,只有少量的存活,那么就选择复制算法
对于老年代,就使用标记-清理或者是标记整理算法

3.垃圾收集器

垃圾回收器就是内存回收的具体实现

3.1 serial收集器

最基本,历史最悠久的
单线程的收集器
在进行垃圾回收的时候,会停掉所有的工作去完成垃圾回收
STOP THE WORLD 造成了很大的恶劣影响

3.2 ParNew收集器

就是多线程版本的serial收集器,但是它可以和CMS通过操作,CMS是具有跨时代意义的,它首次实现了并发收集器,它可以让垃圾收集线程和用户线程共同工作
ParNew是
老年代收集器

3.3 Parallel Scavenge

新生代的收集器使用的是赋值算法,并行的多线程收集器.Parallel Scavenge的目标和其他的垃圾收集器不同,其他的收集器类似于CMS,它们的目的是能够减少用户的停顿,而Parallel Scavenge是为了达到一个可控制的吞吐量
停顿时间适合和用户进行交互的程序,主要就是为了提高用户的体验,高吞吐量则是可以高效率的利用CPU的时间,尽快的完成程序的任务,两者的侧重点不同.

3.4 Serial Old收集器

老年代版本,是一个单线程的收集器,使用的是"标记-清除"算法

3.5 Parallel Old收集器

Parallel Scavenge的老年代版本 使用多线程和"标记-整理"算法

3.6 CMS收集器(****)

目的:为了有更短的停顿时间,为了提高用户体验,因为现在java的应用程序都是运行在B/S的服务端上,应用程序十分重视用户体验
Current Mark Sweep是基于"标记-清除"算法的

缺点

CMS收集器对于CPU资源非常敏感.面向并发的程序都对CPU的资源比较敏感.它不会使得用户程序停止,但是他本身占用了一定的CPU资源,这样会导致应用程序变慢,总的吞吐量会变低CMS默认启动的回收线程数是CPU的数量+3然后再除以4 ,当CPU比较大时,也就是超过了4个,这个时候CMS最多的占有量就是25%,但是如果CPU比较少,这样的话CMS对于用户的影响就会比较大了.如果是两个CPU,这样就有可能让用户程序的执行速度降低了50%.为例解决这一个问题,虚拟机又提供了一种"增量式并发收集器",采用GC线程和用户线程交替着进行
CMS无法处理"浮动垃圾",因为GC线程和用户线程一起运行,这样就会导致用户线程源源不断的产生垃圾,这要的垃圾GC线程没办法在这一次处理它们,所有要留到下一次,这种垃圾被称作是"浮动垃圾".
我们也要为用户线程预留足够多的内存空间.
所以CMS不能再老年代都填满之后才进行收集,需要预留一部分空间
在老年代被占用了68%就会开始垃圾回收
如果预留的内存不够,那么的话就会出现"Current Mode Failure"
CMS是基于标记清除算法的,这样会产生大量的空间碎片

3.7 G1收集器

G1收集器是基于"标记-整理"算法的,所以不会参数空间碎片.
然后它可以精准的控制停顿.
对于原来的收集器都是对整个范围进行回收的,但是G1会将这些内存区域划分冲一个一个的Region,然后根据他们的垃圾堆积程度,在后台维护一个优先的列表,然后优先回收垃圾最多的区域

上一篇 下一篇

猜你喜欢

热点阅读