我已经“修复”了内存泄漏,但是......如何以更好的方式修复它?

时间:2010-08-04 18:51:43

标签: java memory-leaks null final garbage-collection

这是一个非常快速且临时的错误修复程序.. 它有效,但我希望找到更好的理解和解决方案。

这是生成泄漏的类构造函数

final transient  DataInputStream din;
final transient  DataOutputStream dout;
final transient  BufferedReader bin;
final transient  BufferedWriter bout;

NData(Socket sock0) throws IOException
    {
        sock=sock0;
        din= new DataInputStream(sock.getInputStream());
        dout = new DataOutputStream(sock.getOutputStream());
        bin = new BufferedReader(new InputStreamReader(din));
        bout = new BufferedWriter(new OutputStreamWriter(dout));
     //   .. 
    }

错误修复是更改它(删除final),以便让我稍后分配null

transient  DataInputStream din;
transient  DataOutputStream dout;
transient  BufferedReader bin;
transient  BufferedWriter bout;

NData(Socket sock0) throws IOException
    {
        sock=sock0;
        din= new DataInputStream(sock.getInputStream());
        dout = new DataOutputStream(sock.getOutputStream());
        bin = new BufferedReader(new InputStreamReader(din));
        bout = new BufferedWriter(new OutputStreamWriter(dout));
     //   .. 
    } 

 //And to add a "magic" destructor

 void nuller() {
        din=null;
        dout=null;
        bin=null;
        bout=null;
    }

有一个结束线程的结束方法,关闭了流,所以我在那里添加了“nuller”方法调用,并且内存泄漏消失了。

为什么在完成线程并关闭流后,它会继续在“byte []”中分配内存? 为什么GC不扔掉它? (除了那些带有空对齐的脏之后)

修改

卡萨布兰卡说也许NData对象还在, 有一个

final static ConcurrentHashMap <String,NData>(); 

所以将NData作为值,使用remove(key)从Map中清除对象,但是......似乎还不够。

从HashMap中删除唯一的对象引用不足以删除对象吗?

3 个答案:

答案 0 :(得分:4)

  

为什么在完成线程并关闭流后,它会继续在“byte []”中分配内存?为什么GC不扔掉它?

只有在没有对该对象的引用时,GC才会“扔掉”某些内容。在您的情况下,这意味着某些内容仍然包含对NData对象的引用。通过手动调用nuller方法,您只需释放对成员变量的引用(dindout等),但NData对象可能仍然存在。您需要查看其他地方以找出谁正在使用此对象,并确保清除此引用。

更新:您究竟是如何得出内存泄漏的结论? GC仅定期运行,因此不保证立即释放对象。您可以尝试调用System.gc()来强制GC运行。另外,ConcurrentHashMap(我不熟悉)可能是缓存并发的引用,并且在调用remove之后可能不会立即释放它们。

答案 1 :(得分:3)

清理NData对象后,应该进行堆转储。然后在堆中找到NData对象(因为从你的描述中,有人仍然持有它的强引用!)。然后找到该对象如何从root set到达。

最近我必须这样做,我发现使用这些工具很方便:

VisualVM,用于进行堆转储。

Eclipse Memory Analyzer(我单独使用它)来分析堆,特别是从根集中查找路径。

第二个当前比第一个更先进,但第一个的GUI非常好用(如果它也是功能完整!)。

答案 2 :(得分:1)

在你的空调中调用bin.close()和bout.close()就可以了。 只需确保在某个地方的finally块中调用nuller,以便始终调用它。