java学习笔记4_垃圾回收机制

来源:互联网 发布:淘宝网商城炉具大全 编辑:程序博客网 时间:2024/06/01 10:36

JAVA垃圾回收机制的目的

         没做一件事或看一样东西,首先你得至少知道为什么要做,怎么做。java垃圾回收是学习java核心技术的一个重要内容,目前正在学习。以下记录一下学习过程仅供自己整理

目的:防止内存泄露。(换句话说就是对象的生命周期比程序的运行周期周期长即所说的对象游离)

JAVA垃圾回收中的算法

        从时间和版本的顺序来叙述,有早期的引用计数器->(停止复制(stop-and_copy))->标记-清扫(stop-and-sweep)-> 标记-整理算法->copying->generation算法

每一种算法的发展都是为解决前一种算法的不足。

1、引用计数器

        引用计数器是一种简单但速度很慢的回收技术。

原理:给每一对象都包含一个计数器,当有引用连接该对象时便将计时器加1,当离开作用域或对象置为null时,便减1,直到计数器值为0时便回收,释放其占用的空间。

缺点:不适用于交互自引用对象组。(对i像的计数器不可能为0,这样就导致不能被回收)

例子:什么是交互自引用?

public class Main {    public static void main(String[] args) {        MyObject object1 = new MyObject();        MyObject object2 = new MyObject();                  object1.object = object2;        object2.object = object1;                  object1 = null;        object2 = null;    }}
上面的例子定义了两个对像,object1和object2;两个对象相互引用,这种情况就叫做交互自引用(类似于死锁)

2、标记-清扫(mask-and-sweep或者tracing算法)

那么怎样解决上面的交互自引用的问题呢?请看下面stop-and-sweep

原理:程序把所有的引用关系看作一张图,从一个节点GC ROOT开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。(就是说在主线上的保留,其余回收)

图例:

蓝色的为根搜索一条主线上的,其余的将要被回收。这是找到垃圾那么接下来就是回收垃圾

如图,这就是回收的过程。通过根搜索(GCroot)找到垃圾后通过(mark-and-sweep)继续回收,具体过程如下:

(1)首先找到ABC为将要标记(mark)的对象。

(2)通过根集合将没有被标记的对象回收。

缺点:内存中会有碎片(不连续的内存占用)

3、标记-整理算法

标记整理算法就是在标记-清扫算法的基础上进行将最后的内存进行重新排列的


缺点:增加一些句柄和句柄表

4、copying算法

原理:该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。它开始时把堆分成 一个对象面和多个空闲面, 程序从对象面为对象分配空间,当对象满了,基于copying算法的垃圾收集就从根集中扫描活动对象,并将每个 活动对象复制到空闲面(使得活动对象所占的内存之间没有空闲洞),这样空闲面变成了对象面,原来的对象面变成了空闲面,程序会在新的对象面中分配内存。一种典型的基于coping算法的垃圾回收是stop-and-copy算法,它将堆分成对象面和空闲区域面,在对象面与空闲区域面的切换过程中,程序暂停执行。举例如下图:


5、generation算法(代数算法)

分代垃圾回收策略:主要是根据不同对像的生命周期来采取不同的策略。

如上图所示:分为3代,年轻代、年老代和持久代分别从对象的生命周期由长到短进行分开处理。

年轻代(Young Generation)

1.所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。

2.新生代内存按照8:1:1的比例分为一个eden区和两个survivor(survivor0,survivor1)区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空, 如此往复。

3.当survivor1区不足以存放 eden和survivor0的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次Full GC,也就是新生代、老年代都进行回收

4.新生代发生的GC也叫做Minor GC,MinorGC发生频率比较高(不一定等Eden区满了才触发)

年老代(Old Generation)

1.在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

2.内存比新生代也大很多(大概比例是1:2),当老年代内存满时触发Major GC即Full GC,Full GC发生频率比较低,老年代对象存活时间比较长,存活率标记高。

持久代(Permanent Generation)

用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。



未完待续。。。



0 0
原创粉丝点击