【笔记7】消除过期的对象引用

【背景】java虽然有自己的垃圾回收机制,但是并没有那么的智能,对于被引用的对象,就算我们已经不在使用它了,但是java的回收机制是不会回收他们的,人们称之为“内存泄漏”。

【内存泄露场景】

1.只要类自己管理内存,就该警惕内存泄露问题。

如Stack类自己管理内存,在元素出栈,忘记设置为Null时,容易引起内存泄露。

import java.util.Arrays;
import java.util.EmptyStackException;

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];
    }

    /**
     * Ensure space for at least one more element, roughly doubling the capacity
     * each time the array needs to grow
     */
    private void ensureCapacity() {

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

}

先进行入栈5个元素,然后,再出栈5个元素。那么此时,会有5个元素不会被销毁,因为,elements中,持有指向5个对象的引用(保存了5个已经出栈的引用,只有再一次入栈5个引用)。出现内存泄露。进行优化如下:

public Object pop() {

        if (size == 0)
            throw new EmptyStackException();
        Object result = elements[--size];
        elements[size] = null;
        return result;
}

2.内存泄露的另一个常见来源是缓存。

对象引用存放在缓存中,当对象不再被使用时,然后,你忘记将该对象引用从缓存中清理掉。于是,该对象引用会一直保存在缓存中,而你在逻辑上已经没有使用该对象,但是该对象不会被GC回收,因为仍然有引用指向它。

解决办法:关键是,要知道什么时候,缓存中的对象引用不再有用,有意义。在这个时候,就可以清理掉缓存中的对象引用。

一种例子是,如果实现的缓存是这样的:只要在缓存之外存在对某个项的键的引用,该项就有意义;如果没有存在对某个项的键的引用,该项就没有意义。那么,可以使用WeakHashMap来代表缓存。

public class SocketManager {
    private Map<Socket,User> m = new WeakHashMap<Socket,User>();

    public void setUser(Socket s, User u) {
        m.put(s, u);
    }
    public User getUser(Socket s) {
        return m.get(s);
    }
}

 3.内存泄露的第三个常见来源是监听器和其他回调。

如果你实现了一个API,客户端在这个API中注册回调,却没有显式的取消注册,那么除非你采取某些动作,否则,它们会积聚。确保回调立即被当作垃圾回收的最佳方法是只保存它们的弱引用,例如,只将它们保存成WeakHashMap中的键。

【additional】内存泄泄漏通常不会表现成明显的失败,可以在系统中存在很多年,只有通过检查代码,或借助Heap剖析工具才能发现内存泄漏问题。所以要尽量在内存泄漏发生之前就知道如何预测此类问题。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值