服务端开发实战Java

我所知道的-Java垃圾回收机制

2018-07-12  本文已影响8人  WilsonMing
Java垃圾回收机制

本文章你能知道的内容:

Java内存模型

要了解Java垃圾回收机制,首先知道Java内存模型是怎么样的。如下图


Java内存模型

Java 堆

Java Heap 是 Java 虚拟机所管理的内存中最大的一块,它是所有线程共享的一块内存区域。几乎所有的对象实例和数组都在这类分配内存。

Java 堆内存由垃圾回收器的自动内存管理系统管理。
堆内存分为两大部分:新生代和老年代,默认比例为1:2,可修改。
老年代主要存放应用程序中生命周期长的存活对象。
新生代又分为三个部分:一个Eden区和两个Survivor区,默认比例为8:1:1,可修改。
Eden区存放新生的对象。
Survivor存放每次垃圾回收后存活的对象。


堆内存

为什么?

带着这些疑问,我们就要先了解堆相关的垃圾回收算法和采用的垃圾回收器。在讲算法前先了解怎么判断对象是否回收。

对象什么时候回收?

判断对象是否回收主要有以下两种算法

Java定义的GC Roots对象:
虚拟机栈(帧栈中的本地变量表)中引用的对象。
方法区中静态属性引用的对象。
方法区中常量引用的对象。
本地方法栈中JNI引用的对象。

如果出现循环引用了,只要没有被GC Roots引用了就会被回收,完美解决!

垃圾回收算法

知道了什么时候回收对象,那我们再看具体垃圾回收器有哪些垃圾回收算法。

复制算法:适用于存活对象很少。回收对象多
标记整理算法: 适用用于存活对象多,回收对象少

分代算法就是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Old Generation)和新生代(Young Generation),老年代的特点是每次垃圾收集时只有少量对象需要被回收所以采用标记整理法。而新生代的特点是每次垃圾回收时都有大量的对象需要被回收所以采用复制算法(改良的复制算法,不是按1:1分配)。

分代回收算法

// 分配了一个又一个对象
放到Eden区
// 不好,Eden区满了,只能GC(新生代GC:Minor GC)了
把Eden区的存活对象copy到Survivor A区,然后清空Eden区(本来Survivor B区也需要清空的,不过本来就是空的)
// 又分配了一个又一个对象
放到Eden区
// 不好,Eden区又满了,只能GC(新生代GC:Minor GC)了
把Eden区和Survivor A区的存活对象copy到Survivor B区,然后清空Eden区和Survivor A区
// 又分配了一个又一个对象
放到Eden区
// 不好,Eden区又满了,只能GC(新生代GC:Minor GC)了
把Eden区和Survivor B区的存活对象copy到Survivor A区,然后清空Eden区和Survivor B区
// ...
// 有的对象来回在Survivor A区或者B区呆了比如15次,就被分配到老年代Old区
// 有的对象太大,超过了Eden区,直接被分配在Old区
// 有的存活对象,放不下Survivor区,也被分配到Old区
// ...
// 在某次Minor GC的过程中突然发现:
// 不好,老年代Old区也满了,这是一次大GC(老年代GC:Major GC)
Old区慢慢的整理一番,空间又够了
// 继续Minor GC
// ...
// ...
在回答上面提出的问题?
为什么要分新生代和老年代?
综合使用算法,最优采用分代算法所以分为新生代和老年代两块区域。具体为什么1:2?应该是根据实践测试得出的结果,也可以调整。

GC_FOR_MALLOC: 表示是在堆上分配对象时内存不足触发的GC。
GC_CONCURRENT: 当我们应用程序的堆内存达到一定量,或者可以理解为快要满的时候,系统会自动触发GC操作来释放内存。
GC_EXPLICIT: 表示是应用程序调用System.gc、VMRuntime.gc接口或者收到SIGUSR1信号时触发的GC。
GC_BEFORE_OOM: 表示是在准备抛OOM异常之前进行的最后努力而触发的GC。

垃圾回收器

在GC机制中,起重要作用的是垃圾收集器,垃圾收集器是GC的具体实现,Java虚拟机规范中对于垃圾收集器没有任何规定,所以不同厂商实现的垃圾 收集器各不相同,HotSpot 1.6版使用的垃圾收集器如下图(图来源于《深入理解Java虚拟机:JVM高级特效与最佳实现》,图中两个收集器之间有连线,说明它们可以配合使用)


垃圾回收器

参考文章

上一篇下一篇

猜你喜欢

热点阅读