这是一个非常快速且临时的错误修复程序.. 它有效,但我希望找到更好的理解和解决方案。
这是生成泄漏的类构造函数
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中删除唯一的对象引用不足以删除对象吗?
答案 0 :(得分:4)
为什么在完成线程并关闭流后,它会继续在“byte []”中分配内存?为什么GC不扔掉它?
只有在没有对该对象的引用时,GC才会“扔掉”某些内容。在您的情况下,这意味着某些内容仍然包含对NData
对象的引用。通过手动调用nuller
方法,您只需释放对成员变量的引用(din
,dout
等),但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,以便始终调用它。