天天看点

创建和销毁对象——消除过期的对象引用

java 是垃圾回收语言, 但有些对象因为我们的实际代码行为, 无法被jvm 判定可以被回收, 因此这些特殊的对象需要手动清理无法直接被回收的对象, 需要手动处理典型例子 ,以下的例子中. 数组或者 List 或者 Map 中可能有些对象已经无用,但我们不手动移除的话, 他们一直会存在于容器中, 造成垃圾无法被回收class A{ private static B[] b2 = new B[16] ;MapList}

要理解这个问题, 需要理解 jvm 的垃圾回收机制. 这里说的就是因为一些疏忽操作或定义, 导致了部分数据一直无法被回收。这里可能对性能拖累不严重,但是却会占用更多资源,严重者导致oom。

资源未关闭问题,有些随着gc可能会被回收,有些则持续占用,但无论哪种,都可能严重拖累系统性能

public class Stack {
    private Object[] elements;

    private int size = 0;

    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack(){
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(Object e){
        ensureCapacity();
        elements[size ++] = e;
    }

    public Object pop(){
        if (size == 0)
            throw new EmptyStackException();
        return elements[-- size];
    }

    private void ensureCapacity() {
        if (elements.length == size)
            elements = Arrays.copyOf(elements,  2 * size + 1);
    }

}
           

上述代码中存在着内存泄漏,如果向栈中先添加元素再弹出元素,弹出来的对象不会被回收,因为栈内部维护着弹出对象的过期引用。

解决这个问题很简单,将出栈元素的引用设为过期即可:

创建和销毁对象——消除过期的对象引用

这里还要补充一点关于WeakHashMap的知识:WeakHashMap其实是一种弱引用Map,key会存储为弱引用,当GC时,如果这些key没有外部强引用存在的话(当回调对应的强引用被不存在了时),就会被垃圾回收掉。它的这个特性也多被用来实现缓存,如果外面对某个key的引用不存在了,缓存中key对应的这一项就会被自动删除。

例如:使用

WeakHashMap

存储BigImage实例,key是ImageName类型,value是BigImage实例,如果令

imageName = null

 ,这样就没有强引用指向这一个key了,BigImage实例就会在GC时被回收掉

WeakHashMap<UniqueImageName, BigImage> map = new WeakHashMap<>();
BigImage bigImage = new BigImage("image_id");
UniqueImageName imageName = new UniqueImageName("name_of_big_image"); // 强引用

map.put(imageName, bigImage);
assertTrue(map.containsKey(imageName));

imageName = null; //map中的values对象成为弱引用对象
System.gc(); //主动触发一次GC