jvm gc 垃圾回收机制

一、概要

垃圾回收又称gc, gc是运行在Jvm中,回收应用程序中创建的一些无用的对象(学习过Java的人都应该知道)。

前面讲解了几篇相关的内容,大家要了解gc的回收机制,不妨先去看看我上一篇: 
Java Jvm运行机制 http://blog.csdn.net/u011546655/article/details/52175550,好做到一个承上启下的效果。

二、问题概要

大家在学习gc的回收机制之前,还是先带着问题去思考,这样呢,能在最短的时间内,做到最有效的收获。

1.gc是什么东西? 
2.gc是怎么样运行的? 
3.gc的里面的算法是如何实现的? 
4.gc的新老以及永久区是什么? 
5.什么样的垃圾才被回收? 
6.什么时候会导致垃圾回收? 
…. 

三、什么是垃圾

对于垃圾的理解,如果抛开Java语言,大家的理解是怎么样的呢?可能也就是塑料袋,废品,破东西,坏东西。

简而言之:其实所谓的垃圾也就是没有任何价值,没有任何用的东西,那么gc所回收的垃圾,跟这个一样么,往下看。

<span style="color:#000000"><code>1.如何判断它是垃圾?
</code></span>
  • 1
  • 2

刚才已经说了,所谓的垃圾就是没有用的,而gc要回收的东西,也是类似的

Java通过引用来和对象进行关联的,操作一个对象,那么其实是要通过引用来操作的,比如:

User user = new User();

操作对象,其实,我们是使用user这个引用来控制的

比如:user.getAge(); 获取年龄

那么显然意见:这个user对象是有用的,所以它不属于垃圾,另外这样产生的一个对象也属于强引用,而gc一般情况下是不会去回收的。 
PS:如果不了解引用,大家可以去了解下强,软,弱,虚引用的区别。

很简单,反过来,所谓垃圾:其实就是没有引用指向这个对象,也就是说该对象已经没有任何引用,那么它就是垃圾

四、如何判定是“垃圾”

上面已经做了很清楚的,没有任何引用,就视为垃圾,所以判定方法如下:

<span style="color:#000000"><code>方法一:引用计数算法
</code></span>
  • 1
  • 2

1.给对象添加计数器—>如果引用—>计数器+1 
2.引用失效—>计数器-1 
3.任何时刻计数器为0—对象不能再使用

这也就是每一个程序运行,Jvm对于生成,而计数器也是独立的,互不影响

<span style="color:#000000"><code>方法二:根搜索法
</code></span>
  • 1
  • 2

1.GC Roots为起点,从这个节点开始向下搜索 
2.所走过的路劲,使用Wie引用链 
3.对象到GC Roots没有任何链相连,对象不可用

五、那些常见的场景会被回收

如下:

<span style="color:#000000"><code>1.对象被赋值null,或者手动释放
</code></span>
  • 1
  • 2

User user = new User(); 
…. 
user = null;

又如:

Bitmap btimap = Bitmap.createBitmap(src, 0, 0, width, height, m, filter); 
…… 
btimap.recycle();

Android 开发中图片的释放

<span style="color:#000000"><code>2.弱引用
</code></span>
  • 1
  • 2

果一个对象具有弱引用,在GC线程扫描内存区域的过程中,不管当前内存空间足够与否,都会回收内存,使用弱引用 构建非敏感数据的缓存。

弱引用申明:

WeakReferenceweakReference=new WeakReference(new User());

<span style="color:#000000"><code>3.虚引用
</code></span>
  • 1
  • 2

如果一个对象仅持有虚引用,在任何时候都可能被垃圾回收,虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列联合使用,虚引用主要用来跟踪对象 被垃圾回收的活动。

虚引用申明:

PhantomReference phantomReference=new PhantomReference(new User(),new ReferenceQueue());

六、gc回收器

看到上面,大家对gc有一定的了解了,下面我们正式进入大门,去里面看看,gc到底是如何的…

<span style="color:#000000"><code>1.gc的划分
</code></span>
  • 1
  • 2

新域:储存所有生成的对象 
旧域:新域中的对象经过几次gc之后,没有被回收,进入旧域中 
永久域:存储类和方法对象,从配置的角度看,这个域是独立的,不包括在JVM堆内。默认为4M。

如下图:

这里写图片描述

<span style="color:#000000"><code>2.新域
</code></span>
  • 1
  • 2

新域中会被分为三个部分:一个缓冲区,两个休闲区 
新域中,产生的大部分对象都会被回收,少部分进入旧域

1.第一个部分叫做Eden(伊甸园) 
2.辅助的生成空间(幼儿园) 
    A空间… 
    B空间…

<span style="color:#000000"><code>3.旧域
</code></span>
  • 1
  • 2

旧域也被分为几部分,但是旧域中,存活的对象就比较多,所以,旧域中一般回收的对象会比较少

<span style="color:#000000"><code>4.永久域
</code></span>
  • 1
  • 2

一路下来,如果对象还未被回收,那么久会流入永久域中存起来,并不是对象到这里了,gc就不去回收了,只是gc不太会去回收这里面的对象。

七、垃圾回收器算法+新旧永三域

<span style="color:#000000"><code>1.Mark-Sweep算法
</code></span>
  • 1
  • 2

Mark-Sweep算法,也称为:笔记-清除法,这是最基本的垃圾回收器算法,他过程如下:

1.Mark-Sweep分为:标记阶段和清除阶段 
2.标记要回收的对象,清除 回收被标记所占的空间

PS:会导致碎片太多,分配大对象的时候,空间不足,提前触发一次新的垃圾回收操作

这里写图片描述

<span style="color:#000000"><code>1.Copying算法
</code></span>
  • 1
  • 2

上面说了Mark-Sweep算法,有很大的问题,请看红色文字,所以,算法不停的改进,产生了Copying算法,具体情况如下:

1.将内存分为大小相等的两块,每次只使用一块 
2.将活着的对象复制到另一块上,使用的清除掉

PS:不容易产生内存碎片,但是内存会缩减到以前的一半,如果存活对象多,效率会很低,所以可以于新区的时候。

这里写图片描述

<span style="color:#000000"><code>3.Mark-Compact算法
</code></span>
  • 1
  • 2

为了解决,空间浪费的问题,算法继续改进,Mark-Compact算法问世 
具体情况如下:

1.标记阶段和Mark-Sweep一样 
2.完成标记后,不直接清除回收对象,将对象移向一段 
3.清理边界内存

这里写图片描述

<span style="color:#000000"><code>4.Generational Collection算法
</code></span>
  • 1
  • 2

Generational Collection法

分代收集法,听名字就知道,因为我们根据存活的生命周期分为了:新生代,老年代和永久代,也就是新区,旧区和永久区

具体情况如下:

1.根据存活的生命周期将内存分为若干个区:新生代和老年代和永久代 
2.新生代:每次都回收大量对象——>Copying复制法 
3.老年代:每次都回收少量对象——>Mark-Compact法 
4.永久代:存储class类,常量,方法描述:回收废弃常量和无用类

分代收集法:也就是Jvm的垃圾回收所使用的算法,这种算法,既提高了内存空间的使用,而且根据各代的特点,针对处理,减少了cpu的使用率,提高了性能。

以上,差不多就是gc的回收机制了,其实,并没有结束

这里里面还有有些:比如:

1.minor gc/full gc的触发条件? 
2.OOM的触发条件? 
3. 如何降低GC的调优的策略? 
4. 频繁的触发gc的原因?

猜你喜欢

转载自blog.csdn.net/baishimingbaishiming/article/details/81712779