我已经“修复”了内存泄漏,但是..如何以更好的方式修复它?
这是一个非常快速且临时的错误修复。 它有效,但我想找到更好的理解和解决方案。
这是生成泄漏的类构造
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));
// ..
}
函数错误修复是更改它(删除最终),以便让我稍后分配 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 作为值的 so,执行了删除(key)以从 Map 中清除对象,但是..这似乎还不够。
从 HashMap 中删除唯一的对象引用不足以删除该对象?
It was a very fast and makeshift, bug fix..
It worked, but I would like to find a better understanding and solution.
This was the Class Constructor generating the leak
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));
// ..
}
The bug fix was to changed it (remove final) so that let me to assign null later
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;
}
There was a finish method that ended the thread, closes the streams, so I add there the "nuller" method call, and memory leak went away.
Why after finished the thread and closed the stream, it keep allocating memory in "byte[]" ?
Why GC don't throw it away ? (except after that dirty with null asignment)
EDIT:
As casablanca says perhaps the NData object is still around,
there is a
final static ConcurrentHashMap <String,NData>();
so that have NData as values, A remove(key) is done to purge the object from the Map, but.. it seems not be enough.
Removing from a HashMap the only object reference won't be enough to remove the object?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
仅当不再有对该对象的引用时,GC 才会“丢弃”该对象。在您的情况下,这意味着某些东西仍然持有对 NData 对象的引用。通过手动调用
nuller
方法,您只需释放对成员变量(din
、dout
等)的引用,但NData
对象可能仍然存在。您需要在其他地方查找谁在使用该对象,并确保该引用已清除。更新:您到底是如何得出存在内存泄漏的结论的? GC 仅定期运行,因此不能保证对象立即被释放。您可以尝试调用 System.gc() 来强制 GC 运行。此外,
ConcurrentHashMap
(我不熟悉)可能会缓存并发引用,并且在调用remove
后这些引用可能不会立即释放。The GC will "throw" something away only when there are no more references to that object. In your case, this means that something is still holding a reference to the
NData
object. By manually calling yournuller
method, you simply release the references to the member variables (din
,dout
etc.) but theNData
object is probably still lying around. You need to look elsewhere to find out who is using this object and make sure that this reference is cleaned up.Update: How exactly did you come to the conclusion that there is a memory leak? The GC only runs periodically, so objects are not guaranteed to be freed immediately. You could try calling
System.gc()
to force a GC run. Also,ConcurrentHashMap
(which I'm not familiar with) might be caching references for concurrency and it's possible that these aren't freed immediately after callingremove
.清理 NData 对象后,您应该进行堆转储。然后在堆中找到NData对象(因为从你的描述来看,有人仍然持有对它的强引用!)。然后找出如何从根集访问该对象。
最近我不得不这样做,我发现使用这些工具的过程很方便:
VisualVM,用于获取堆转储。
Eclipse Memory Analyzer(我独立使用它)来分析堆,特别是查找来自根集。
目前,第二个比第一个先进得多,但第一个的 GUI 非常好用(如果它的功能也很完整的话!)。
You should take a heap dump after you cleaned up the NData object. Then find the NData object in the heap (because from your description, someone is still holding a strong reference to it!). Then find how is this object reachable from the root set.
Recently I had to do this, and I found the process convenient using these tools:
VisualVM, for taking the heap dump.
Eclipse Memory Analyzer (I used it standalone) to analyze the heap, in particular find the paths from the root set.
The second currently is significantly more advanced than the first, but the GUI of the first is very nice to use (if it was also feature-complete!).
在你的 nuller 中调用 bin.close() 和 bout.close() 就可以了。
只需确保 nuller 在某个地方的 finally 块中被调用,这样它总是被调用。
In your nuller call bin.close() and bout.close() That will do it.
Just make sure that the nuller is called in a finally block somewhere so it always gets called.