很早就想对Java的GC做点小总结,一直没有时间,最近看了下java paper上的java gc文章,觉得不错,读了读,顺便做下总结。
java paper的GC文章地址,里面有很多java技术文章,写的都不错。
1、Java GC 简介
JVM的垃圾回收机制使开发者不必过多考虑内存的申请与释放,这样降低了软件开发的成本和语言的学习成本。
不同的JVM对GC的实现是不同的,目前Oracle维护着两种JVM,JRockit JVM,HotSpot JVM。
本文讨论的JVM是居于HotSpot的JVM。
1、运行时数据区域
方法区、Heap内存,Java Stack, PC Registers,本地方法栈
(以下图片均来自网络)
2、执行引擎
JIT Compiler, Garbage Collector
2、Heap Memory
在运行时,java对象的实例均被分配在heap内存中。当对象不被引用的时候,会被垃圾回收器标记为eviction,然后回收,最后释放在heamp中所占用的空间。
Java Heap Memory 分为三个区域:
1、Young Generation
1、Eden 任何实例进入运行时的内存区域都是从Eden进入的
2、S0 存活久一点的实例就可以从Eden进入到S0
3、S1 存活更久的实例从S0进入S1
2、Old Generation
tenured (终身制的),实例从S1晋升到终身制区域
3、Permanet Generation
包含元数据信息,如class,method的detail信息
翻译一段来自java paper的Heap介绍:
Eden Space:
每当一个实例被创建,就会分配到eden空间。
Survivor Space (S0 and S1):
作为minor GC的一部分,对象如果还在被引用的,就会从移动到S0.
在minor GC时,如果对象没有被引用了,该对象就会被标记为要驱逐出内存中的对象。
Old Generation:
老年代是heap memory的逻辑部分,当垃圾收集器进行minor GC的时候,S1中还在存活的对象实例将从S1 移动 到 Old, 在S1中失去引用的部分,将被标记为从内存中驱逐。
Major GC:
老年代中的对象在进行Major GC时,那些失去引用的对象将被标记为从内存中驱逐。
Memory Fragmentation:
内存片段:当实例从heap memory中删除时,被删除后内存位置可以供新分配的对象使用,内存碎片需要被整理成连续的空间,内存碎片整理,从而能进行快速的分配内存空间。
在驱逐对象实例和恢复内存空间之前,要对对象实例调用finalize()方法来对 该对象实例持有的资源进行释放。
尽管finalize()方法一定在恢复内存空间前执行,但是顺序是无序的,是没有规定时限的。对象多实例之间的释放顺序不能提前决定,它们甚至可能是并行的进行。
3、GC 过程
Young 和 Old 的关系是 晋升关系
联想起来,其实可以这样打个比方,就是学生上学的场景:
Heap Memory中的GC就是上学的问题。
我们把这几个区域比作学校。实例比作学生。
Young
Eden S0 S1
小学 初中 高中
Old
大学
Permanet
学生元信息库
描述GC的过程就很通俗易懂啦。
判断是否晋升,是否标记释放,可以用reference来判断。那么:
still referenced 仍然被引用的 (就是仍然愿意学习学生)
dereferenced 失去引用的(就是不愿意学习的学生)
MinorGC:(发生在Young内)
1、比如一个学生刚上学,那么他肯定首先分配到小学,即Eden。
2、如果在小学里还想继续学习的学生,即still refernced的学生,就会晋升到初中S0进行学习。不想学习的学生,即dereferenced 会被标记为毕业,会被垃圾回收。
3、如果在初中里还想继续学习的学生,即still refernced的学生,就会晋升到高中S1进行学习。即dereferenced 会被标记为毕业,会被垃圾回收。
MajorGC:(发生在Old)
当在高中毕业后S1,还想继续学习的,那么就会被晋升到大学Old。
发生MajorGc时,Old中会回收失去引用的实例,还被引用的将不被回收,还在Old大学里继续学习。当大学里装的学生太多了,就会触发OutOfMemoryError了。
(以下图片来自网络)
4、对象的回收
什么情况下对象会被回收?
Strong Reference Not eligible for garbage collection - 强引用的对象实例不会被回收
Soft Reference Garbage collection possible but will be done as a last option - 软引用的对象实例可能会被回收,但是一定是在不得不回收的情况下才回收。
Weak Reference Eligible for Garbage Collection - 弱引用的肯定会被回收
Phantom Reference Eligible for Garbage Collection - 幽灵引用的肯定会被回收
1、声明后从来都没使用的对象,编译器会自动给该对象置为null,会被编译器标记为eviction。
编译器会将那么不会在后续使用的对象,在运行时之前提前将其提前回收。
2、典型的一个例子,一个实例的所有属性都存在register中,访问实例的属性值是从register中读取的,如果这个实例在未来不会将属性值写回实例,那么该实例还是会被标记为驱逐。
3、null值赋给实例,如果该实例没有其它实例的引用,则会被标记回收。
4、当finalize方法被调用,JVM会释放在那个线程的所有同步锁。
5、总结
JVM是一套标准,有很多种实现,我们最常接触的是HotSpot JVM,对于不同的JVM,垃圾回收器的实现也不同。
JVM中主要是分为运行时数据区域 和 执行引擎。
Heap Memory中被划分为Eden,S0,S1,Old,Perm
GC的过程就是这Eden到S0,S0到S1,S1到Old的晋升过程,分为minorGC 和 MajorGC(FullGc)。
强引用对象不会被垃圾回收,软引用一般情况下不会被回收,实在不能回收时最后才会被回收。 弱引用和幽灵引用的都会被回收。
——EOF——
原创文章,转载请注明出自:http://blog.csdn.net/oopsoom/article/details/40348125