Java堆内存垃圾回收机制(GC)详解 (引用计数法,根搜索法详解)

来源:互联网 发布:java 异或加密 字符串 编辑:程序博客网 时间:2024/06/06 06:11

什么对象需要回收
在Java堆中存放着Java程序中新建的对象,也就是我们开发过程中 new,newarray 创建的对象。但没有明确的代码去释放他们。垃圾回收机制就是释放这些不再被程序所使用的对象的过程。

为什么要使用垃圾收集器
在虚拟机的堆内存中,当某些对象失去引用,对于虚拟机内存而言就是”垃圾”,虚拟就就会回收这部分内存,以供后续的新对象使用。除了释放不在被引用的对象外,
在堆空间中,并不是所有的内存空间都是连续的,因为在程序运行过程中每次新建对象都会申请堆内存,并不能保证内存可以整齐的码放在你面前。要是申请不到大片连续的内存区域,还可能造成“内存不足”的假象。

引用计数法
引用计数法是垃圾回收的早期策略,在堆中的每个对象都有一个引用来计数,每当有一个地方引用到它时,计数器的值就会加一;引用失效时,计数器值减一,当计数器的值为0时,就认为该对象就是不被使用的,可以进行垃圾回收,但这种算法缺钱,就是很难解决对象之间相互循环引用的问题;

public static void main(String[] args) {        GcObject obj1 = new GcObject(); //Step 1        GcObject obj2 = new GcObject(); //Step 2        obj1.instance = obj2; //Step 3        obj2.instance = obj1; //Step 4        obj1 = null; //Step 5        obj2 = null; //Step 6    }}class GcObject{    public Object instance = null;}

百度图

 当程序进行到Step 1 时 obj1 的计数器=1; 当程序进行到Step 2 时 obj2 的计数器=1; 程序进行到Step 3 时 obj1 的计数器=2; 程序进行到Step 4 时 obj2 的计数器=2;

此时obj1,obj2的技术都为2;
当程序进行到Step 5 时 obj1 的计数器-1 结果为1;
当程序进行到Step 6 时 obj2 的计数器-1 结果为1;如下图
这里写图片描述
那么如果采用的引用计数算法的话 GcObject实例1和实例2的计数引用都不为0,两个实例所占内存不到释放,于是就产生了内存泄露。

根搜索法(可达性算法)
根搜索法是通过一系列称为”GC Root”的对象作为起点。以这些节点作为根节点向下搜索,搜索过程中的路径成为“”引用链“”,当某个对象到”GC Root”没有任何引用链时,也就是“根对象”不可达。就被认为是可以被回收的对象,
“”GC Root“”对象包括以下几种:
虚拟机栈中的引用的对象;
方法去中类静态引用的对象;
常量引用的对象;
这里写图片描述
如上图中,GC Root对object1,object2,object3,object4都是仍存活的对象,object5,object6,object7都是GC Root 触及不到的,因此都时要被回收打的内存。

对于垃圾收集器力来说,堆中每个对象都有三种状态,可触及的,可复活的,不可触及的。不可触及的也就是我们刚提的 GC Root引用链连接不到的对象。对于另外的两种,可触及打的,是指每个对象从他生命的开始起,只要程序至少保留一个可触及的引用,那么它就是可触及的,一旦程序释放了所有对该对象的引用,那么这个对象就成了可复活状态。若满足以下条件则为可复活状态:   从根节点连接不到,但是可能在垃圾收集器执行某些终结方法时触及;**不仅仅是声明了finalize()方法的对象,而是所有的对象都要经过可复活状态**    先来说finalize()方法,如果类中声明了此方法,垃圾回收器(GC)会在释放这个实例占据的内存空间之前,执行这个方法如下
class Final(){protected void finalize(){   System.out.println("Final obj die!");   //go die   }}

根搜索算法中不可达对象在回收之前,要进行二次标记。
第一次标记时会进行一次筛选:筛选的条件是是否有必要执行finalize()方法。
当对象没有覆盖finalize()方法,或者finalize()被虚拟机调用过,则虚拟机认为没有必要执行finalize()方法。
如果这个对象有必要执行finalize(),则会放在一个队列里,以一个低优先级的线程进行执行finalize()方法进行二次标记,如果在finalize()方法中,对象重新回到引用链上(比如this赋值给其他引用链上的对象),则该对象不被回收,而移出该队列。
注意:finalize()方法只被调用一次,如果这个对象在GC时被调用过一次finalize()方法,则第二次GC的时候,就会被判断为没有必要执行finalize()而被直接回收。
另外finalize()能做的所有工作,都可以通过try-finally更好、更及时的解决。所以请忘掉finalize().

    public class TestGc {          public static TestGc HOOK;          @Override          protected void finalize() throws Throwable {              super.finalize();              TestGc.HOOK = this;              System.out.println("finalize");          }          /*               输出结果         finalize         HOOK is alvie         HOOK is dead          */          public static void main(String[] args) throws Exception {              HOOK = new TestGc();              HOOK = null;              System.gc();//第一次GC,符合有必要要执行finalize的条件              Thread.sleep(500);//Finalizer线程优先级较低,所以要等一会              if (HOOK != null) {                  System.out.println("HOOK is alvie");              } else {                  System.out.println("HOOK is dead");              }              HOOK = null;              System.gc();//第二次GC,因为已经执行过一次finalize,所以没有必要进行二次标记              Thread.sleep(1000);//Finalizer线程优先级较低,所以要等一会              if (HOOK != null) {                  System.out.println("HOOK is alvie");              } else {                  System.out.println("HOOK is dead");              }          }      }  

无论是引用计数法,还是跟搜索法都是引用操作,那么就有可能产生垃圾问题,但是对于引用也需要有一些合理化的设计。在很多的时候并不是所有的对象都需要被我们一直使用,那么就需要对引用的问题做进一步的思考。从JDK1.2之后关于引用提出了四种类型的引用:
demo 引自http://blog.csdn.net/qq_34280276/article/details/52863626;
●强引用:也就是我们new出来的对象当内存不足的时候,JVM宁可出现OutOfMemory错误停止,也需要进行保存,并且不会将此空间回收(永远不会被GC回收);

public class Demo{    public static void main(String[]args){        Object obj=new Object();//强引用,默认        Object ref=obj;//引用传递        obj=null;//断开连接        System.gc();        System.out.println(ref);    }}

●软引用:当内存不足的时候,进行对象的回收处理,往往用于高速缓存中;

public class Demo{    public static void main(String[]args){        Object obj=new Object();        SoftReference<Object> ref=new SoftReference<Object><obj>;//软引用        obj=null;//断开连接        System.gc();        System.out.println(ref.get());    }}

如果此时内存空间充足,那么对象将不会回收,如果空间不充足,则会进行回收。

public class TestDemo{    public static void main(String[]args){        Object obj=new Object();        String str="hello";        obj=null;//断开连接        SoftReference<Object> ref=new SoftReference<Object><obj>;//软引用        try{            for(int x=0;x<Inter.MAX_VALUE;x++){                str+=str+x;                str.intern();            }        }catch(Throwable e){        }                   System.out.println(ref.get());    }}

●弱引用:无论内存够不够,下一次内存收集之前都会进行;

弱引用本质的含义指的是说只要一进行GC处理,那么所引用的对象将会被立刻回收。弱引用需要使用的是Map接口的子类:java.util.WeakHashMap。
范例:观察弱引用

package cn.test.demo;import java.lang.ref.SoftReference;public class TestDemo{    public static void main(String[]args){        String key=new String(“hi”);        String value=new String(“hello”);        Map<String,String> map=new WeakHashMap<String,String>();        map.put(key,value);        System.out.println(map.get(key));        key=null;        System.out.println(map);        System.gc();        System.out.println(map);    }}  

一旦出现GC,则必须进行回收处理,而且一回收一个准。
HashMap与WeakHashMap区别?
HashMap是强引用,而WeakHashMap是弱引用。

在java.lang.ref包中存在有一个WeakReference的一个子类。
范例:观察WeakReference

package cn.test.demo;import java.lang.ref.SoftReference;public class TestDemo{    public static void main(String[]args){        String key=new String(“hi”);        WeakReference<String> map=new WeakHashMap<String>(key);        Key=null;        System.out.println(ref.get());        System.gc();        System.out.println(ref.get());    }}

弱引用之所以不敢轻易使用的原因,就是因为其本身一旦有了GC之后就会立刻清空,这个对于程序的开发不利。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 固定孔螺丝滑丝怎么办 小螺丝拧不出来怎么办 小螺丝拧不下来怎么办 螺丝拧的太紧怎么办 大螺母拧不下来怎么办 大螺帽拧不出来怎么办 十字螺丝滑丝了怎么办 六角螺母拧圆了怎么办 饺子冻在盘子上怎么办 煮熟的饺子坨了怎么办 六角螺丝拧圆了怎么办 长杆螺丝滑丝了怎么办 起泡器不起泡了怎么办 不喂母乳涨奶怎么办 螺丝和螺母跟转怎么办 六棱螺丝滑丝了怎么办 苹果6螺丝滑牙了怎么办 外六角螺丝圆了怎么办 小螺丝拧花了怎么办 老人退伍证丢了怎么办 狗狗又拉又吐怎么办 孕妇吃了马兰头怎么办 怀孕吃了马兰头怎么办 吃了茭白和豆腐怎么办 电气焊加工怎么办环评 手上皮肤干燥起皮怎么办 脸上起皮怎么办还痒痒 店铺4周被释放了怎么办 炫舞账号忘了怎么办 椎基底供血不足怎么办? 脑动脉供血不足怎么办 颈椎引起的脑供血不足怎么办 军人保障卡怎么办假的 正常形态精子率低怎么办 前向运动精子21怎么办 前向运动精子22%怎么办 前向运动精子19%怎么办 前向运动精子为0怎么办 被蝎子草扎了怎么办 二年级孩子成绩差怎么办 长治医保卡丢了怎么办