• 深入Java---垃圾回收


    • 1.垃圾回收器:

       Java中垃圾回收一般都是在Java堆中进行,Java堆存放几乎Java中所有的对象,Java堆被叫做GC堆,Java垃圾一词,指的是没有任何变量去引用它,JVM认为其是垃圾信息,可以被回收, 垃圾回收器 使用 有向图来记录和管理内存中所有的对象。

     垃圾回收器三项任务:①分配内存 ② 确保被引用对象不被错误的回收 ③ 回收再也没有变量引用的对象。

      在JDK1.2 对引用进行扩充:强引用 、软引用、弱引用、虚引用

      强引用:Object obj=new Object(), 只要强引用还存在,垃圾回收器不会回收被引用对象

    • 2.垃圾回收算法:

      垃圾回收通过一定算法进行计算出哪些对象是可以被回收:

    • 引用计数算法:很难解决对象之间相互循环引用问题

         给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1,当引用失效时,计数器值就减1,任何时刻计数器都为0的对象就是不可能再被使用的。 引用计数算法的实现简单,判定效率也很高,在大部分情况下它都是一个不错的选择,当JVM并没有选择这种算法来进行垃圾回收,主要原因是它很难解决对象之间的相互循环引用问题。

    •    追踪回收算法:利用JVM维护有向图,从根节点遍历图同时对对象进行标记,遍历结束后没有被标记的对象就可以被回收,inalize()方法在对象空间被回收之前进行调用,这个对象逃脱被销毁最后一次机会finalize()方法让该对象 与引用链上任何对象建立关联关系。
    •  复制回收算法:将堆内存平均分为两部分,任何时刻,只使用其中一块内存,当一块内在用完之后,将存活的对象复制到之外的内存中,将此内存进行clear  优点:垃圾回收同时对对象进行安排,避免了内存碎片,缺点:降低内存使用空间,内存调整过程中中断当前程序,降低程序的执行效率
    • 按代价回收算法:对复制回收算法的进步:程序创建大部分对象生命周期很短,小部分对象生命周期较长: 将堆分成多个堆,每一个子堆视为新一代,先收集年幼对象,如果发现某个对象在多次收集过程存活,将其移动到高级堆。

     3.是否通过通知JVM 进行垃圾回收:

      由于垃圾回收器存在,Java语言本身没有显示释放内存的方法,开发人员不能够时实调用垃圾回收器对某个对象进行垃圾回收,但是通过System.gc()方法通知垃圾回收器进行回收,代价:执行会停止所有的程序响应,去单独检测是否有对象可以进行回收---不推荐频繁使用


    4.垃圾回收的代码分析:

     在使用代码分析,对内存分配策越明确之下的三点

     ① 对象优先进入Eden分配 ②大对象直接进入老年代 ③长期存活的对象将进入老年代

    1 public class SlotGc{
    2     public static void main(String[] args){
    3         byte[] holder = new byte[32*1024*1024];
    4         System.gc();
    5     }
    6 }

    在JavaC编译之后采用如下的指令: Java-verbose:gc SlotGc:发现 32MB内存并没有完全释放 holder变量还在作用域中

     修改:

    1 public class SlotGc{
    2     public static void main(String[] args){
    3         {
    4         byte[] holder = new byte[32*1024*1024];
    5         holder = null;
    6         }
    7         System.gc();
    8     }

    首先确定一点:holder是否释放根本原因在于 局部变量表中Slot是否还存在 对holder对象组的引用

    在第一次代码中 在holder作用域之外进行回收,但是在此之后并没有对局部变量表中Slot进行修改,保留原先值,所以并没有释放内存

    在第二次将局部变量表中slot=null,回收器会将holder 之前引用对象进行全部回收

        当然采用方式对holder引用对象进行回收,只要 对holder所占用的slot修改即可

    1. 问题一:Java 垃圾回收机制 如何判断一个对象是否die?

    JVM管理的堆中内存,几乎存放存放所有的对象实例,如果一个对象在程序中没有任何引用指向他,那么该内存对象可以被收回,因此将 没有任何引用指向此对象 说明这个对象是Die,是可以被回收的对象。Java中通过引用与对象进行关联,操作对象必须对此对象进行引用,一种最简单的办法通过引用计算的方法判断对象是否被回收,但是这种方法无法解决循环引用的问题。

    垃圾回收器:回收的是无任何引用的对象占用的空间不是这个对象 。回收老的空间给新的对象进行使用。JVM通过。

    System.gc()  /  Runtime.getRuntime().gc() 显示的通知JVM进行一次垃圾回收。事实真正的垃圾回收时间不可预料的,主要和线程抢占有关系。

    注意:System.gc() 并不能JVM立即做出垃圾回收反应只是让垃圾回收能够更加的容易提前发生

    2. 垃圾回收算法:

     

    • 引用计数算法(利用对象中引用计算器--无法解决循环引用)
    • Tracing 回收(利用JVM维护对象的引用图,遍历有向图没有被标记的图像就可以被回收)
    • 压缩回收算法(带来性能损伤)
    • 复制回收算法(堆内存分为两块相同区域,任何时刻只有一个内存块被使用,内存耗尽将对象 紧凑复制到另外一块内存中 消除堆碎片但是增大的内存空间)
    • 按代价回收(大部分对象短暂的生命周期,较小对象较长生命周期 ,将经过多次收集存活的对象转移到高一级堆中,减小扫描次数)
    3.finalize()方法:作用处理通过其他方式(C++ malloc 函数)开辟内存空间 或者垃圾回收器无法处理的对象
          通知回收器不能处理特性对象在回收之前进行资源的释放,特性对象 打开的文件资源或者通过调用C++中malloc函数分配的空间没有调用free函数释放。
    调用finalize函数的对象只有在下一次的垃圾回收的动作时候才会真正释放回收,本次不会

     

      

    二. Java的GC堆中垃圾引用垃圾回收机制,自动进行垃圾回收 为什么Java中还是存在内存泄漏问题?

    Java中内存空间是否被回收两个标准: ① 对象赋予NULL,之后没有被使用过 ②对象赋予新值重新分配了内存。 内存泄漏有两种情形:堆中申请new的内存没有被释放(Java垃圾回收机制)②不在使用对象还有内存 这样垃圾回收机制无法保证对象被释放。经典实例:不断循环创建对象加入到Vector容器中 如下图:

    Vector v=new Vector();
    for(int i=0;i<10;i++)
    {
           Object o=new Object();
            v.add(o);
    }

    退出循环o作用域over 但是v使用这些对象 导致垃圾回收器无法回收o对象。

     

     

    Java语言中 内存泄漏问题很多:主要以下方面:

     1).静态的集合类:HashMap和Vector静态的容器,生命周期与程序一样长,那么其中不使用对象不会释放

             不使用集合之后将其进行 clear

     2)各种动态链接 数据库连接,网络连接和IO连接,显示的进行连接的关闭

    3). 监听器

    4).变量不合理作用域:定义范围大于其使用范围+没有及时将对象设置null 不使用对象没有设置成null

    5).单例模式可能引起内存释放。

     

  • 相关阅读:
    蛋糕多少钱?
    【FJOI2015】金币换位问题
    撞车
    【BZOJ 1097】旅游景点atr
    codeforces 434D
    codeforces 480D
    bzoj网络流
    bzoj2039
    bzoj1927
    bzoj1070
  • 原文地址:https://www.cnblogs.com/woainifanfan/p/6804032.html
Copyright © 2020-2023  润新知