详解GC回收机制

GC回收是按照五种算法实现的

1.引用计数算法

   效率较高,但是无法回收循环引用的对象

2.根搜索算法

   它的处理方式就是,设立若干种根对象,当任何一个根对象到某一个对象均不可达时,则认为这个对象是可以被回收的

   GC root有几下种:

  • Class - 由系统类加载器(system class loader)加载的对象,这些类是不能够被回收的,他们可以以静态字段的方式保存持有其它对象。我们需要注意的一点就是,通过用户自定义的类加载器加载的类,除非相应的java.lang.Class实例以其它的某种(或多种)方式成为roots,否则它们并不是roots,.
  • Thread - 活着的线程
  • Stack Local - Java方法的local变量或参数
  • JNI Local - JNI方法的local变量或参数
  • JNI Global - 全局JNI引用
  • Monitor Used - 用于同步的监控对象
  • Held by JVM - 用于JVM特殊目的由GC保留的对象,但实际上这个与JVM的实现是有关的。可能已知的一些类型是:系统类加载器、一些JVM知道的重要的异常类、一些用于处理异常的预分配对象以及一些自定义的类加载器等。然而,JVM并没有为这些对象提供其它的信息,因此需要去确定哪些是属于"JVM持有"的了。

3.标记/清除算法

       标记:标记的过程其实就是,遍历所有的GC Roots,然后将所有GC Roots可达的对象标记为存活的对象。

       清除:清除的过程将遍历堆中所有的对象,将没有标记的对象全部清除掉。

       这种算法的缺点就是效率比较低且清理出来的空闲内存是不连续的

4.复制算法

     复制算法将内存划分为两个区间,在任意时间点,所有动态分配的对象都只能分配在其中一个区间(称为活动区间),而另

     外一个区间(称为空闲区间)则是空闲的。

     当有效内存空间耗尽时,JVM将暂停程序运行,开启复制算法GC线程。接下来GC线程会将活动区间内的存活对象,全部

     复制到空闲区间,且严格按照内存地址依次排列,与此同时,GC线程将更新存活对象的内存引用地址指向新的内存地址。

     此时,空闲区间已经与活动区间交换,而垃圾对象现在已经全部留在了原来的活动区间,也就是现在的空闲区间。事实上,

     在活动区间转换为空间区间的同时,垃圾对象已经被一次性全部回收。

     这种算法的缺点就是内存消耗大,浪费了一半的内存

5.标记/整理算法

    标记:它的第一个阶段与标记/清除算法是一模一样的,均是遍历GC Roots,然后将存活的对象标记。

   整理:移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收。因此,第二阶段 

   才称为整理阶段。 

   标记/整理算法唯一的缺点就是效率也不高

总结:

后面三种算法是根据根搜索算法判断是否应该被回收,而支撑根搜索算法可以正常工作的理论依据,就是语法中变量作用域的相关内容。因此要想防止内存泄露,最根本的办法就是掌握好变量作用域。 

猜你喜欢

转载自blog.csdn.net/fengzhiqi1993/article/details/81197046