zoukankan      html  css  js  c++  java
  • 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/


  • 相关阅读:
    使用ABP构建WebAPI的心得
    修改andriod模拟器的IMEI,IMSI,手机号,SIM卡号
    Abp框架下 Area中新建Layout报错的问题
    通过Roslyn构建自己的C#脚本 资料记录
    EF5 CodeFirst 修改主键自增属性
    Oracle字段类型及存储(一)
    ArcMap之等值面
    街景初看
    转:oracle中schema指什么
    OSGI起程一——确定目标
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/6847944.html
Copyright © 2011-2022 走看看