JVM 垃圾回收机制( 一) 回收对象的判定

关于JVM 的垃圾回收机制,我们一般都没过多深入,因为JAVA 和 C++ 的一个很大区别就是,JAVA 帮我们做了垃圾回收,而不用像C++ 那么样手动进行回收,当然任何自动的东西都存在一定弊端,比如机器人,即使自动程度很高,但是在处理某些感情问题上,肯定处理上就会有遗漏,开个玩笑啦, 下面我们先来了解一下JVM 的垃圾回收是怎么回事。

一、如何判断对象已经死亡

JVM 会回收那些不在使用的对象,或者说是已经死亡的对象,从而达到节省空间的目的,那么我们肯定的判断哪些对象已经死了,不在使用呢?

1 引用计数算法:

这算法原理很简单,就是当我们的对象没引用的时候,有一个计数器,比如count,就会count
++,同理,如果被应用的对象设为null,那么count --,直到 count = 0的为止。当JVM
 进行回收的时候,那么他会找到这些count = 0 的对象,默认没有被使用,就进行回收了。

这个算法,理论上是挺好的,但是当对象相互引用的时候就无法进行了,举个例子:比如A 类,里面有个B类的引用
b,同时B类里面有个A类的引用a,当我们同时A a= new A(),B b = new B();这时候是一个强引用,都会count
++,当我们让里面的引用a.b =b,b.a=a;的时候就是第二次引用,count 都变成了2,如果这时让

a =null,b =null,count -- ,当我们回收的时候发现count = 1;JVM 就不会回收了,那么就会浪费内存,这也是引用计数算法的主要劣势,这里也顺便分析下这种算法:

1.   需要单独的字段存储计数器,增加了存储空间的开销;

2.       每次赋值都需要更新计数器,增加了时间开销;

3.       垃圾对象便于辨识,只要计数器为0,就可作为垃圾回收;

4.       及时回收垃圾,没有延迟性;

5.       不能解决循环引用的问题;

2 可达性分析算法

这种算
法可以对象循环引用的问题,基本原理是:通过一个叫“GC
ROOT”根对象作为起点,然后向下节点搜索,搜索路径叫引用链,也就是我们常说的引用,当我们从ROOT
找不到任何一条路径相连的对象的情况下,就可以判定可以回收了,相当于这对象找不到家的感觉,这里引用JVM的图:

2 .1 GC ROOT 回收对象的范围包括:

a. 虚拟机栈(栈帧中的本地变量表)中引用的对象

b. 方法区中类静态属性引用的对象

c. 方法区中常量引用的对象

d. 本地方法栈中JNI(native方法)引用的对象

关于一些堆栈 方法区的分布作用,以后再讲,可以先参考:

http://www.360doc.com/content/11/0504/12/3903749_114271703.shtml

虽然有可达性分析算法来判定对对象状态,但这并不是对象是否被回收的条件,对象回收的条件远远比这个复杂,比如无法通过ROOT找到的对象,也不一定会回
收,会进入一个死缓的阶段,那些无法通过根节点
引用链找到的对象,会被第一次标记,并进行一次筛选,筛选条件是此对象是否有必要执行finalize()方法,当对象没有覆盖finalize()方
法,或者finalize() 方法已经被虚拟机调用过,虚拟机都视为“没必要执行”。

如果该对象被判定为有必要执行finalize(),那么对象会被放置在一个F-Queue
的队列中,并由一个优先级较低的Finalizer 线程去执行,这里的执行是 JVM
会触发这个方法,但并不保证等待他运行结束,因为finalize() 方法执行慢,或者死循环,会影响该队列其他元素执行。

执行finalize() 方法就会进行第二次标记,然后等待JVM 进行回收了,而在finalize() 方法执行的同时,可以对对象进行“拯救”,也就是说在执行方法内部,再次对对象进行引用,那么对象就复活了,看代码:

Java代码  

  1. package com;
  2. import java.lang.reflect.Method;
  3. import org.springframework.cglib.proxy.MethodInterceptor;
  4. import org.springframework.cglib.proxy.MethodProxy;
  5. public class FinalizeGC{
  6. public static FinalizeGC save_gc = null;
  7. public static void main(String[] args) throws InterruptedException {
  8. save_gc = new FinalizeGC();
  9. // 断掉引用链
  10. save_gc = null;
  11. // 调用finalize 回收,里面进行了 拯救 行动
  12. System.gc();
  13. // finalize 优先级比较低,暂停0.5秒等待他执行
  14. Thread.sleep(500);
  15. System.out.println("该对象状态是--->"+save_gc);
  16. // 这里代码同上,但是已经拯救无效
  17. save_gc = null;
  18. System.gc();
  19. Thread.sleep(500);
  20. System.out.println("该对象状态是--->"+save_gc);
  21. }
  22. // 重写该方法
  23. @Override
  24. protected void finalize() throws Throwable {
  25. super.finalize();
  26. System.out.println("正在执行 finalize 方法");
  27. // 从新引用
  28. FinalizeGC.save_gc = this;
  29. }
  30. }
  31. 结果:
  32. 正在执行 finalize 方法
  33. 该对象状态是--->com.FinalizeGC@c17164
  34. 该对象状态是--->null

可以看出,finalize
在GC的时候已经执行了,并且对象已经被拯救了,但是发现只被执行了一次,也就只能被拯救一次,因此有一个有值,有一个是null.这里可以看出JVM
对对象的finalize()只会被执行一次,这里仅仅做了解,不建议重写该方法,因为这样会干扰对象的回收调用机制,而且运行代价很高。

除了上述那些对象以外,还有一些废弃常量的回收,比如:有一个一个字符串"ABC" 已经进入常量池中,但是当前系统没有任何地方引用该对象,该常量就会被清除常量池。

同时还有一些废弃的类,或者无用的类也会被回收,这里一些判定条件有:

a.该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例

b.加载该类的ClassLoader 已经被回收

c.该类的java.lang.Class 对象在没有任何地方呗引用,无法在任何地方通过反射访问该类的方法。

小结:

1.这里仅描述了一些JAVA 对象是否可以回收的一些判定方法和条件

2.关于还有垃圾收集的一些算法以及垃圾回收器,这些才是描述JVM 如何整理这些分布在内存中的过期对象,如何进行批量的手机 删除工作的,这个以后再解释吧。

时间: 2024-10-18 05:16:43

JVM 垃圾回收机制( 一) 回收对象的判定的相关文章

JVM 垃圾回收机制(1)

文章出处:http://www.cnblogs.com/lzrabbit/p/3826738.html JVM内存回收机制简述(转载) 目前java的jdk默认虚拟机为HotSpot,因此本文涉及虚拟机相关内容都指HotSpot虚拟机 本文主要关注GC的回收:判断哪些对象可回收,如何回收,回收机制 判断哪些对象可回收 GC是通过对象是否存活来决定是否进行回收,判断对象是否存活主要有两种算法:引用计数算法.可达性分析算法 引用计数算法引用计数的算法原理是给对象添加一个引用计数器,每被引用一次计数器

Java垃圾回收机制(未掌握)

垃圾回收机制 任何一种垃圾回收算法一般要做两件基本事情: 发现无用的对象(没有任何变量引用该对象) 回收无用对象占用的内存空间 垃圾回收相关算法: 引用计数法, 引用可达法 分代垃圾回收机制: 不同的对象的生命周期是不一样的. 因此, 不同生命周期的对象可以采用不同的回收算法, 以便提高回收效率. 将对象分为三种状态: 年轻代, 年老代, 持久代. JVM虚拟机将堆划分为Eden, Survivor和Tenured/Old空间 年轻代 所有新生的对象首先是都放在Eden区. 年轻代的目标就是尽可

java垃圾回收机制简介

1.背景 传统C 或C++是程序员负责回收已分配的内存,也就是显示进行垃圾回收.因为程序员不知道内存应该何时释放,所以会导致一些分配出去的内存得不到回收,造成 "内存泄漏" .导致系统运行速度下降,程序瘫痪. 2.什么是内存泄漏? 一些分配出去的内存得不到回收,导致系统运行速度下降,甚至程序瘫痪的现象. 3.显示回收垃圾的缺点: 1)程序忘记及时回收无用内存,导致内存泄漏,降低系统性能 2)程序错误回收程序核心类库,导致系统崩溃 4.java中的垃圾回收机制 ,也就是GC (Garba

java 垃圾回收机制

1. java的垃圾回收机制主要工作包括:确定哪些对象属于垃圾,回收无用的对象占用的空间,使堆中的存活对象紧密排列. 2. Java垃圾回收的算法: 引用计数(基本不用): 当引用指向一个对象时,该对象的引用计数器+1: 当引用离开对象挥着被标记为null时,引用计数器-1: 当引用计数器为0时,释放对象占用的空间. 缺陷:如果对象间存在循环引用,可能会发生对象无法被回收的情况. 停止-复制: 对象发现: 从堆栈和静态存储区出发遍历所有引用,找到引用的对象以及该对象包含的所有引用,从而找到所有活

Java基础知识总结之垃圾回收机制

垃圾回收机制 Java死亡垃圾回收机制是Java语言的重要功能之一.当程序创建对象,数组等引用类型对象时,系统会自动在内存区为之分配一块内存,对象就保存在这块内存区内,当这块内存不再被任何变量引用时,这块内存就成为了垃圾,等待垃圾回收机制进行回收. 垃圾回收机制的特征 1.垃圾回收机制只负责回收堆内存中的对象,不会回收任何物理资源(例如数据库连接.网络连接.IO流等资源). 2.程序无法精准控制垃圾回收的运行,垃圾回收会合适的时候进行.当对象永久性地失去引用后,系统就会在合适的时候回收塔

php垃圾回收机制

垃圾回收机制 房子(对象) 钥匙(变量)  只要有人还有钥匙(还有变量指向对象),房子(对象)不能销毁,一旦钥匙(变量)被销毁,房子(对象)也就销毁了 执行析构函数:要么对象已经被销毁,要么对象未销毁,但程序已执行完毕 程序一执行完毕,对象自动被销毁. 垃圾回收机制是单纯的"引用计数",也就是每个内存对象都分配一个计数器,当内存对象被变量引用时,计数器 1:当变量引用撤掉后,计数器-1:当计数器=0时,表明内存对象没有被使用,该内存对象则进行销毁,垃圾回收完成

Yaffs2文件系统垃圾回收机制诠释

悲剧,图片贴不出来... 回收顺序: 一)回收最老块(500次回收才进行一次回收) 二)回收最老的脏块(有优先回收的前提下) 三)回收最老的优先回收块(有优先回收的前提下)(这里目前我认为是优先回收且为最老的脏块) 四)回收最脏(脏指在阀值范围内)且最老的块(正常情况下) 五)回收最老的脏块(这种情况是多次找不到回收块,说明当前的系统很干静,可回收的垃圾很少): 思考点: 1.出现ECC纠正的块,是否有必要超过三次进行坏块标记? 2.出现ECC错误的块,是否有必须回收? 3.垃圾回收时是否可以进

图解Java内存回收机制

在Java中,它的内存管理包括两方面:内存分配(创建Java对象的时候)和内存回收,这两方面工作都是由JVM自动完成的,降低了Java程序员的学习难度,避免了像C/C++直接操作内存的危险.但是,也正因为内存管理完全由JVM负责,所以也使Java很多程序员不再关心内存分配,导致很多程序低效,耗内存.因此就有了Java程序员到最后应该去了解JVM,才能写出更高效,充分利用有限的内存的程序. 1.Java在内存中的状态 首先我们先写一个代码为例子: Person.java package test;

Java的内存回收机制

在Java中,它的内存管理包括两方面:内存分配(创建Java对象的时候)和内存回收,这两方面工作都是由JVM自动完成的,降低了Java程序员的学习难度,避免了像C/C++直接操作内存的危险.但是,也正因为内存管理完全由JVM负责,所以也使Java很多程序员不再关心内存分配,导致很多程序低效,耗内存.因此就有了Java程序员到最后应该去了解JVM,才能写出更高效,充分利用有限的内存的程序. 1.Java在内存中的状态 首先我们先写一个代码为例子: Person.java 1 2 3 4 5 6 7