How to detect memory leak issue

首先,托管代码由GC自动回收,不代表托管应用程序就没有内存泄露问题

其次, 程序不总是精确知道哪些托管对象是垃圾,这就代表着没有一款工具,一运行就能给你一个报表,说某某对象没回收,某某地方发生了内存泄露。

再次, 工具只能dump出当前应用程序的内存快照,有没有内存泄露还需要你敏锐的眼光。比如说下面的例子,当某个文档被关闭后,这个文档对象及其它引用的资源依然包含在Dump的内存快照中,我们就可推断出此处有内存泄露。

 

Tool:

I used the .Net Memory Profiler tool to investigate this issue. You can get a fully functional 14 day trial version form here, and there are some training stuff list here.

Suggestion:

· If any plug-in listen system events which will adds into EventManager (Application level object), please make sure remove the handlers before closing document.

· Avoid implement empty destructors in C#,  try to implement IDisposable interface to dispose unmanaged and managed resource in Dispose method,  or  use dispose pattern. if any incorrect place, please correct me.

(In book of “CLR VIA C#” chapter 20, page 477, Jeffrey Richter mentioned: “the CLR doesn't make any guarantees as to the order in which Finalize methods are called, so you should avoid writing a Finalize method that accesses other objects whose type defines a Finalize method; those other objects could have been finalized already. )

 

Now, please refer to the following explanation why we need to notice those.

Diagnosis:

  • To make it more clear, I add two commands in Windows class  , this will force GC to collect garbage:

clip_image003

  • Next, run the application, create a default document , then close the document. Run the .Net Memory Profiler tool, and attach it to the application process, then execute “Collect heap Snapshot” command. Now, Profiler will analyze the memory of the application. This process is very slow, in the end, we can see  the following snapshot:

1

  • Filter the Namespace to select the namespace - “xxx.xxx.xxx.xxx.Documents.Objects”, we can see there is still a copied IllustrationDocument object. However, we expect it should be 0. This tells us the IllustrationDocument object don’t  be disposed successfully.

2

  • Double click the IllustrationDocument row, we can get this instance’s details information that also includes its reference

3

  • Now we found there are 19 references. But some references have no problems like Asset, because the asset object’s lifecycle is in the scope of document’s lifecycle. Check the “Only show instance included in root paths” checkbox, it will filter the references, and only show the instances included in root paths. Those references are the really killers who caused to the IllustrationDocument object couldn’t be disposed successfully:

4

(The row which mark up by red rectangle is caused by the Renderer class, which forgot to remove system  events handler in its dispose method)

  • Double click the highlight row in the above figure, we can look over which objects have references to ShotEditor instance:

5

  • Go on (double click the highlight row in above figure), then refer to the following:

7

  • Go on…, finally we get the following figure:

6

Reason: The CameraEvents has been added into EventManger class whose lifecycle is global. Any class who listens camera’s events, will cause it still keep to live, so the CLR could not mark them as garbage. This is the real reason for that we could not dispose document object successfully.

Solution:

Let’s have a look at CtxMenuForm source code, we will find it listens the OnCameraEventChange event in its construction, but forget to remove this event handler.

So let’s do some changes for it, implement the IDisposable interface:

8

Then call  form’s dispose method in someplace before close the document :

clip_image002

Collect the Application memory snapshot again following above steps,  we will found the root references count reduce from 4 to 3, has no referenced by ShotEditor.

The some problems also exist in Renderer class and some UI class, after I do some changes for those class, remove all listened events handlers before close document, I finally remove all the root references to IllustrationDocument object, but there is still a copied IllustrationDocument object. I don’t know what’s wrong, then I refer it to MSDN, and got the following infomation:

Implementing Finalize methods or destructors can have a negative impact on performance and you should avoid using them unnecessarily. Reclaiming the memory used by objects with Finalize methods requires at least two garbage collections.

You can get more information from here.

So, I modify the Windows class, try to call GC.Collect method more than twice, run the Application application, close the default document, collect its memory snapshot, the result is there is still a copied IllustrationDocument object. I am confused! Then I turn to write a small test application, it works as MSDN said. So what’s wrong?

clip_image027

After some struggle, I build a release version, then I found the document can complete dispose successfully. Refer to the following figure:

9

Hope it helps.

原文地址:https://www.cnblogs.com/anders06/p/1882606.html