GC入门指南(二)------GC工作原理

本系列博客旨在帮助大家理解java垃圾收集器及其工作原理,这是系列的第二篇。

java垃圾回收其实是由一个可以进行自动内存管理的进程完成的,这使得程序员在写代码的时候不必过多考虑内存释放与回收的问题。


垃圾收集器如何初始化:
作为一个自动化的进程,程序员并不需要显式地在代码中初始化垃圾收集进程。所谓的 System.gc()和Runtime.gc()都属于请求JVM初始化垃圾收集进程的钩子函数。尽管这种请求机制为程序员提供了一个初始化该进程的机会,但是实际上控制权仍掌握在JVM手中。也就是说JVM可以选择忽略程序员的请求,因而不要指望虚拟机能够足够听话。事实上,它总是基于堆内存Eden区域的内存分配情况来作出判断。而具体的判断方式虚拟机规范上并没有强制要求,这个因不同虚拟机实现而异。

垃圾收集进程:

垃圾收集就是一个回收无用空间使之将来可以重新分配给其他对象用的进程。

Eden区域:当实例被创建,优先存储在新生代的Eden区域。

Survivor区域(S0和S1):作为Minor GC(新生代GC)生命周期的一个步骤,Eden区域中的存活对象将会被移到S0区域,而S0区域中的存活对象在被GC扫描之后将会被移到S1区域。而死亡对象将会被GC标记,
被标记的对象可能会在标记后由此进程去回收也可能由一个单独的进程去回收(有四种类型的垃圾收集器,下篇我们将会学习)。

老年代:老年代是堆内存的另一个逻辑组成部分,gc执行完MinorGC之后,某些在S1区域中依旧存活的对象
将会晋升到老年代(译者注:并不是所有对象都能够晋升,只有熬过若干次MinorGC的对象才能晋升,这里有个对象年龄的概念,具体可参见专栏其他文章),而无用对象将会被标记。

MajorGC:MajorGC其实就是老年代GC,在此期间,垃圾收集进程会扫描老年代中所有对象,标记死亡对象,被标记的对象随后将会被回收而其他对象依旧存活。

内存碎片:当被标记的对象被清除后,堆内存会出现一些“空洞”,即内存碎片。为了提高对象分配的速度,我们应该清除掉这些内存碎片。当然,这取决于具体的gc回收器实现。


实例的终结:
对象实例被回收之前,垃圾收集器可能会调用其finalize方法,因而对象可以在此方法中进行一些资源释放的操作( 译者注:没有复写finalize方法的对象似乎并不需要执行其父类的finalize方法,参考《深入理解java虚拟机 JVM高级特性与最佳实践》3.2.4节),尽管finalize方法在该对象被回收前是一定会被执行的,但是确并没有一个明确的时间和明确的顺序,多个待回收的实例调用finalize方法的先后顺序不可以被设置,它们甚至会并行的执行。 译者注:这里说的执行finalize方法仅仅指触发这个方法,但虚拟机不承诺等待其运行结束,因为如果finalize方法执行时间过长,将会影响其他对象的回收,甚至导致整个内存回收系统崩溃

1.如果在回收一个垃圾对象的过程中出现异常,默认将会被忽略,并且取消回收该对象实例。
2.虚拟机规范并没有对虚引用的垃圾回收过程进行强制规定,细节由虚拟机实现者决定。
3.垃圾回收过程是由一个守护线程执行的。


对象何时能回收:
1.一个线程访问不到该对象实例;
2.该对象(或者是若干对象循环引用)不被任何其他对象所引用。
(译者注:上面定义不是很直观,其实这里有个根引用算法以及GC root的概念,具体参见专栏其他文章)

java中有不同的引用类型,垃圾回收因引用类型而异。

在java编译器编译优化期间,可以选择给一个对象赋null表示该对象不再可用,可以被回收。

class Animal {
    public static void main(String[] args) {
        Animal lion = new Animal();
        System.out.println("Main is completed.");
    }
    protected void finalize() {
        System.out.println("Rest in Peace!");
    }
}

上面代码中,lion对象在被声明后没有被使用过,所以java编译器作为一个编译优化措施可以通过添加lion=null在声明lion之后,所以在main方法的输出之前,finalize方法就已经输出“rest in Peace!”了,当然了,我们并不能保证输出这样的结果,因为这取决于虚拟机实现以及内存使用情况。
(译者注:如果没有执行垃圾回收,则上述代码并不会调用finalize方法)但是我们学到一点,那就是编译器可以选择提前释放一个对象实例如果其预见到该对象将来不会被使用。
描述GC范围的示例代码:

Class GCScope {
	GCScope t;
	static int i = 1;
	public static void main(String args[]) {
		GCScope t1 = new GCScope();
		GCScope t2 = new GCScope();
		GCScope t3 = new GCScope();
		// No Object Is Eligible for GC
		t1.t = t2; // No Object Is Eligible for GC
		t2.t = t3; // No Object Is Eligible for GC
		t3.t = t1; // No Object Is Eligible for GC
		t1 = null;
		// No Object Is Eligible for GC (t3.t still has a reference to t1)
		t2 = null;
		// No Object Is Eligible for GC (t3.t.t still has a reference to t2)
		t3 = null;
		// All the 3 Object Is Eligible for GC (None of them have a reference.
		// only the variable t of the objects are referring each other in a
		// rounded fashion forming the Island of objects with out any external
		// reference)
	}
	protected void finalize() {
		System.out.println("Garbage collected from object" + i);
		i++;
	}

GC OutOfMemoryError示例:
java世界也会有内存溢出问题。
import java.util.LinkedList;
import java.util.List;
public class GC {
	public static void main(String[] main) {
		List l = new LinkedList();
		// Enter infinite loop which will add a String to the list: l on each
		// iteration.
		do {
			l.add(new String("Hello, World"));
		} while (true);
	}
}

输出:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.LinkedList.linkLast(LinkedList.java:142)
	at java.util.LinkedList.add(LinkedList.java:338)
	at com.javapapers.java.GCScope.main(GCScope.java:12)
下篇我们将介绍不同的垃圾收集器类型。

原文:http://javapapers.com/java/how-java-garbage-collection-works/


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值