系统相关
首页 > 系统相关> > 深入Java虚拟机第二部分--垃圾收集器与内存分配策略(2)

深入Java虚拟机第二部分--垃圾收集器与内存分配策略(2)

作者:互联网

深入Java虚拟机第二部分--垃圾收集器与内存分配策略

垃圾收集器与内存分配策略

1.概述

说起垃圾收集(Garbage Collection,GC),大部分人都把这项技术当做Java语言的伴生产物。事实上,GC的历史比Java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言。当Lisp还在胚胎时期时,人们就在思考GC需要完成的3件事情:

经过半个多世纪的发展,目前内存的动态分配与内存回收技术已经相当成熟,一切看起来都进入了“自动化”时代,那为什么我们还要去了解GC和内存分配呢?答案很简单:当需要排查各种内存溢出、内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节

回到我们熟悉的Java语言。上一章介绍了Java内存运行时区域的各个部分,其中程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,随线程而灭; 栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作。每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的因此这几个区域的内存分配和回收都具备确定性,在这几个区域内就不需要过多考虑回收的问题,因为方法结束或者线程结束时,内存自然就跟随着回收

而Java堆和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期间时才能知道会创建哪些对象,这部分内存的分配和回收都是动态的,垃圾收集器所关注的是这部分内存,本章后续讨论中的“内存”分配与回收也仅指这一部分内存。
了。

2.对象已死吗(如何判断对象已经死亡)

在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”(即不可能再被任何途径使用的对象)。

2.1 引用计数算法

引用计数算法的缺陷测试代码

/**
*testGC()方法执行后,objA和objB会不会被GC呢?
*@author zzm
*/
public class ReferenceCountingGC{
public Object instance=null;
private static final int_1MB=1024*1024;
/**
*这个成员属性的唯一意义就是占点内存,以便能在GC日志中看清楚是否被回收过
*/
private byte[]bigSize=new byte[2*_1MB];
public static void testGC(){
ReferenceCountingGC objA=new ReferenceCountingGC();
ReferenceCountingGC objB=new ReferenceCountingGC();
objA.instance=objB;
objB.instance=objA;
objA=null;
objB=null;
//假设在这行发生GC,objA和objB是否能被回收?
System.gc();
}
}

2.2 可达性分析算法

2.3 再谈引用

2.4 生存还是死亡

即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程:

一次对象自我拯救的演示

class FinalizeEscapeGC{
    public static FinalizeEscapeGC SAVE_HOOK=null;
    public void isAlive(){
        System.out.println("yes,i am still alive:)");
    }
    @Override
    protected void finalize()throws Throwable{
        // finalize()
        super.finalize();
        System.out.println("finalize mehtod executed!");
        FinalizeEscapeGC.SAVE_HOOK=this;
    }
    public static void main(String[]args)throws Throwable{
        SAVE_HOOK=new FinalizeEscapeGC();
//对象第一次成功拯救自己
        SAVE_HOOK=null;
        System.gc();
//因为finalize方法优先级很低,所以暂停0.5秒以等待它
        Thread.sleep(500);
        if(SAVE_HOOK!=null){
            SAVE_HOOK.isAlive();
        }else{
            System.out.println("no,i am dead:(");
        }
//下面这段代码与上面的完全相同,但是这次自救却失败了
        SAVE_HOOK=null;
        System.gc();
//因为finalize方法优先级很低,所以暂停0.5秒以等待它
        Thread.sleep(500);
        if(SAVE_HOOK!=null){
            SAVE_HOOK.isAlive();
        }else{
            System.out.println("no,i am dead:(");
        }
    }
}

在这里插入图片描述

回收方法区(给我点时间)

标签:Java,finalize,收集器,对象,虚拟机,回收,引用,内存
来源: https://blog.csdn.net/weixin_44684812/article/details/117780484