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

发布于 2024-09-13 02:07:20 字数 1624 浏览 8 评论 0原文

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

这是生成泄漏的类构造

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

葬花如无物 2024-09-20 02:07:20

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

仅当不再有对该对象的引用时,GC 才会“丢弃”该对象。在您的情况下,这意味着某些东西仍然持有对 NData 对象的引用。通过手动调用 nuller 方法,您只需释放对成员变量(dindout 等)的引用,但 NData 对象可能仍然存在。您需要在其他地方查找谁在使用该对象,并确保该引用已清除。

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

Why after finished the thread and closed the stream, it keep allocating memory in "byte[]" ? Why GC don't throw it away ?

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 your nuller method, you simply release the references to the member variables (din, dout etc.) but the NData 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 calling remove.

丶视觉 2024-09-20 02:07:20

清理 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!).

薄荷港 2024-09-20 02:07:20

在你的 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文