美文网首页
第二部分-垃圾回收

第二部分-垃圾回收

作者: 炫迈哥 | 来源:发表于2017-08-20 19:53 被阅读0次

应用计数器法没办法规避循环引用,忽略它。。。

跟搜索算法root节点:

  • 虚拟机栈,本地方法栈中引用的对象
  • 方法区引用的类静态变量(java8后已经属于堆了) // TODO 待确认
  • 方法区中的常量引用的对象(java8后已经属于堆了) // TODO 待确认

java的强软弱虚引用

  • 强引用不多说,jvm无论如何都不会回收有强引用的对象
  • 软引用,内存快溢出前会回收软引用对象。(安卓端一些图片缓存,全部放进内存又太大,从磁盘慢慢读又太慢,那就用软引用缓存)
  • 弱引用,不确定的时间回收,垃圾收集器发现弱引用对象就会回收它。WeakHashMap就是弱引用的map实现,它的key是关联到一个软引用的,一旦key在外面不存在引用了,会被自动清除。可以将ReferenceQuene传入WeakHashmap的构造方法(constructor)中,这样,一旦这个弱引用指向的对象成为垃圾,这个弱引用将加入ReferenceQuene。看个例子:
import java.util.HashMap;  
import java.util.Iterator;  
import java.util.Map;  
import java.util.WeakHashMap;  

public class Test {  
    public static void main(String[] args) throws Exception {  
        String a = new String("a");  
        String b = new String("b");  
        Map weakmap = new WeakHashMap();  
        Map map = new HashMap();  
        map.put(a, "aaa");  
        map.put(b, "bbb");  

          
        weakmap.put(a, "aaa");  
        weakmap.put(b, "bbb");  

        map.remove(a);  

        a=null;  
        b=null;  

        System.gc();  
        Iterator i = map.entrySet().iterator();  
        while (i.hasNext()) {  
            Map.Entry en = (Map.Entry)i.next();  
            System.out.println("map:"+en.getKey()+":"+en.getValue());  
        }  

        Iterator j = weakmap.entrySet().iterator();  
        while (j.hasNext()) {  
            Map.Entry en = (Map.Entry)j.next();  
            System.out.println("weakmap:"+en.getKey()+":"+en.getValue());  

        }  
    }  

      
}  

当把a和b都置为null后,hashmap中也不存在对它的引用了(remove掉了),外边a也被置null了,weakhashmap将会自动移除a为key的记录,b虽然被置为null了,但是new String("bbb")出来的对象在hashmap中还存在引用,所以不会被回收。
(弱引用最大的用处是,你需要用一个对象,但也只是用一用,不能影响它的垃圾回收,比如需要监控虚拟机中某些对象的属性值,如果直接用强引用获取,那么被监控的对象将不会被gc回收,此时弱引用就派上了用场)

  • 虚引用,它唯一的作用就是跟ReferenceQueue一起使用,通知对象被回收。
import java.lang.ref.PhantomReference;  
import java.lang.ref.Reference;  
import java.lang.ref.ReferenceQueue;  
import java.lang.reflect.Field;  
  
public class Test {  
    public static boolean isRun = true;  
  
    @SuppressWarnings("static-access")  
    public static void main(String[] args) throws Exception {  
        String abc = new String("abc");  
        System.out.println(abc.getClass() + "@" + abc.hashCode());  
        final ReferenceQueue<String> referenceQueue = new ReferenceQueue<String>();  
        new Thread() {  
            public void run() {  
                while (isRun) {  
                    Object obj = referenceQueue.poll();  
                    if (obj != null) {  
                        try {  
                            Field rereferent = Reference.class  
                                    .getDeclaredField("referent");  
                            rereferent.setAccessible(true);  
                            Object result = rereferent.get(obj);  
                            System.out.println("gc will collect:"  
                                    + result.getClass() + "@"  
                                    + result.hashCode() + "\t"  
                                    + (String) result);  
                        } catch (Exception e) {  
                            e.printStackTrace();  
                        }  
                    }  
                }  
            }  
        }.start();  
        PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc,  
                referenceQueue);  
        abc = null;  
        Thread.currentThread().sleep(3000);  
        System.gc();  
        Thread.currentThread().sleep(3000);  
        isRun = false;  
    }  
}  


我们可以声明虚引用来引用我们感兴趣的对象,在gc要回收的时候,gc收集器会把这个对象添加到referenceQueue(如上例中,abcWeakRef虚引用就对abs这个对象感兴趣,abc被回收时会被放入referenceQueue中,我们只用监听referenceQueue就知道哪些对象被回收了),这样我们如果检测到referenceQueue中有我们感兴趣的对象的时候,说明gc将要回收这个对象了。此时我们可以在gc回收之前做一些其他事情(如安卓图片滚动显示,每次只显示一张图片,但是图片特别大,内存只能容得下一张图片的大小,此时就需要虚引用来监听前一张图片是否已经被移除,移除之后才能加载下一张图片进来)

finalize方法

没有实现finallize方法的对象不会执行这一堆逻辑,对象回收时干的事情,执行后对象会被放入F-queue中,如果此时对象又被引用上,对象将起死回生。每个对象虚拟机只会执行一次finalize方法。建议对象回收监听使用虚引用(幽灵引用)来实现。

回收方法区

  • 回收常量池

某个字符串已经没有任何引用指向它时即可回收。

  • 回收类条件
  1. 没有任何类实例(全部被回收)
  2. 加载该类的类加载器已经被回收
  3. 类的Class对象没有在任何地方被引用(不能反射创建实例)

类回收相关虚拟机参数:

  • -verbose:class可以查看类加载信息
  • -XX:+TraceClassLoading,-XX:+TraceClassUnLoading可以查看类的加载和卸载信息。

垃圾收集算法

  • 标记清除
  • 复制
  • 标记整理
  • 分代收集

垃圾收集器

  • Seria收集器(串行收集器,单线程,采用复制算法)年轻代收集器

  • ParNew(和Seria一样,只是多线程版本而已)年轻带收集器

  • SeriaOld 串行收集器,老年代版本,但是使用标记整理算法。

  • CMS并发老年代收集器。(标记清除)
    初始标记,并发标记,重新标记,并发清除。

  • G1收集器:http://blog.csdn.net/renfufei/article/details/41897113 待学习

内存分配回收策略

  • 优先分配到eden区域

参数:-Xms20M -Xmx20M 堆最小值及最大值,-Xmn10M堆的新生代大小,设置为10MB后,老年代大小就为20m-10m=10m了。 -XX:SurvivorRatio=8代表survicor:eden=1:8,设置为8后,新生代中eden区域就占8/10,两个survivor分别占1/10;

  • 大对象(大数组或超长字符串)直接进入老年代

因为对象太大先存入eden区,再进survivor进行复制算法拷贝代价就会比较大。
可以使用虚拟机参数-XX:PretenureSzieThreshold:13723来设定判断大对象的阈值(需要注意,这里单位默认为b,写的时候不能自定义单位,另外,只有parNew和Seria收集器会识别该参数)

  • 长期存活对象进入老年代

并发那一块的笔记里对对象头的介绍,除了偏向锁等信息等之外就有一个age属性,记录对象的垃圾收集年龄,在survivor区每次被复制都会+1,虚拟机默认达到15岁进入老年代,可以手动设置年龄阈值,-XX:MaxTenuringThreshold:5

tips:虚拟机有另外一个动态年龄判断规则,如果某个年龄的对象大小占据了survivor区的一半,则会将年龄大于等于该年龄的所有对象晋升到老年区。

  • 空间分配担保

担保,就是年轻代没有容纳能力了,老年代替你存。(这里老年代替年轻代存的是新的需要分配空间的对象还是survivor区的最老的对象?????!!!回答:当然是最老的对象了咯,除非是大对象)
!!空间分配担保是一直都开启的,HandlePromotionFailure参数只是设置是否允许担保失败。

HandlePromotionFailure参数配置的影响:每次minorgc前先判断老年代是否能容纳全部当前年轻代的大小,成立->直接minorgc即可,不成立-> (老年代剩余空间小于平均晋升大小 || 不允许担保失败 -> fullgc , else -> minorgc)

结论:

  1. HandlePromotionFailure设置成了false,每次minorgc时只要老年代容不下所有年轻代了,都会被改为fullgc!!
  2. 设置为true后,只有靠平均晋升大小来判断是否触发fullgc了,这样的经验判断,肯定会有失误的时候,一旦某次晋升对象大小大于经验值,此时会再触发一次fullgc
  3. 所以,一般都会将HandlePromotionFailure设置为true,不要让虚拟机频繁的fullgc

相关文章

  • JVM垃圾回收机制

    JVM垃圾回收 整体思维导图 带着问题理解JVM垃圾回收机制 Java为什么需要垃圾回收机制; 回收哪部分垃圾; ...

  • JVM GC 回收机制与分代回收策略

    1 垃圾回收 说到垃圾回收(Garbage Collection,GC),大部分人都把这项技术当做java语言的伴...

  • 2.1GC系列-------如何进行回收(方法论)

    本篇针对第二个问题:如何对垃圾进行回收-方法论 首先讲解垃圾回收算法,垃圾回收算法是一个演变的过程。 标记-清除算...

  • 简单理解垃圾回收

    什么是垃圾回收? 垃圾回收的是什么? 如何判断为垃圾? 垃圾是怎样被回收的? 垃圾回收哪些区域的内存? 什么是垃圾...

  • 2018-05-29 第二十三天

    一、垃圾回收 1:java 的内存分为三部分 栈:stack 局部变量。 栈内存的回收,自动回收,方法结束,就回收...

  • JVM(二) GC算法与分代回收策略

    可达性分析 GCRoot场景 垃圾回收算法 分代回收策略 引用 垃圾回收 垃圾回收(Garbage Collect...

  • JVM调优之垃圾定位、垃圾回收算法、垃圾处理器对比

    谈垃圾回收器之前,要先讲讲垃圾回收算法,以及JVM对垃圾的认定策略,JVM垃圾回收器是垃圾回收算法的具体实现,了解...

  • 01垃圾回收机制

    垃圾回收(Garbage Collection,GC) 垃圾回收就是释放垃圾占用的空间 内存的动态分配和垃圾回收,...

  • Java 垃圾收集(GC)浅谈

    Java 垃圾收集(GC)浅谈 为什么需要垃圾回收?哪些内存需要回收?什么时候回收?如何回收? 为什么需要垃圾回收...

  • 垃圾回收

    如何查看当前JVM使用的垃圾回收器? 如何指定使用CMS回收? 如何打印回收日志? 垃圾回收过程 CMS垃圾回收的...

网友评论

      本文标题:第二部分-垃圾回收

      本文链接:https://www.haomeiwen.com/subject/xtzfdxtx.html