Leak disappears on taking snapshot

Hello,

We are facing a unusual situation with our code. We have memory leak in our application because of which there are multiple operations  (same operation repeated n times) when we do action. This behaviour is consistent.

Now as soon as we take snapshot using dotMemory, the application works correctly and there are no leaks. Only one instance remains. 

This problem is pretty awkward. may be we have some initialisation wrong way, but it is difficult to find the retention path since there is nothing in snapshot. We did tried collecting GC explicitly but that didnt helped. 

I tried some other tools like .Net Memory Profiler and ants but issue behaves same way. So, its not a problem with tool itself. 

Any help would be appreciated. 

5 comments
Comment actions Permalink

Hello,

dotMemory (and other profilers) calls full GC on taking memory snapshot. Microsoft profiling API is working in this way, profiler initiates garbage collecting and gathers an object graph during GC.

We have a suggestion why memory issues occur when profiler is not attached only. Concurrent GC may cause it. Full GC is never called in concurrent GC mode. Concurrent GC is always disabled when you run your program under profiler or attach profiler to the process.
Please disable concurrent GC in your app.config file to verify it.

Also we can suggest you to analyze memory traffic. Traffic analysis can help you to determine ineffective memory usage in your app. 

0
Comment actions Permalink

HI Anna, 

Thanks for response. i shall check what you suggested, but just a quick query. Based on input on some forum, we have tried to use following  as explicit additional check when at particular points. 

GC.Collect(0, GCCollectionMode.Forced, true);
GC.Collect(1, GCCollectionMode.Forced, true);
GC.Collect(2, GCCollectionMode.Forced, true);
GC.WaitForPendingFinalizers();

Does dotmemory call GC differently to this, if we run in Non-concurrent mode ?

0
Comment actions Permalink

Our profiler calls GC from a native code.

When you call GC.Collect() method from your code, it performs the next steps:

- Release memory which can be released immediately
- Find the objects which have Finalize methods and put them in a queue

GC.Collect() release only a managed objects. Besides, CLR has several different GC strategies which are applied depending on the situation to minimize delay which caused GC and we can't affect it.
Native memory which used by managed objects will never been released if these objects don't have Finalize method or this method is implemented incorrectly.

We can suggest you to call WaitForPendingFinalizers method with GC.Collect and repeat it several times:

  for (int i = 0; i < 4; i++)
  {
    GC.Collect();
    GC.WaitForPendingFinalizers();
  }

It can show the better result when you release memory from your code.

0
Comment actions Permalink

More powerful method is:

  for (int i = 0; i < 4; i++)
  {
    GC.Collect(2, GCCollectionMode.Forced, true);
    GC.WaitForPendingFinalizers();
  }

But we can't guarantee that this code will lead to the same results as Full GC called from native code.

GC.Collect - https://msdn.microsoft.com/en-us/library/hh138633(v=vs.110).aspx

Forces a garbage collection from generation 0 through a specified generation. So, based on the description, you don't need call GC.Collect for each generation, only specify the oldest.

 

0
Comment actions Permalink

@Vineetyadavonline Did it work for you ?

0

Please sign in to leave a comment.