5

Possible Duplicates:
Is it possible to have a memory leak in managed code? (specifically C# 3.0)
Memory Leak in C#

There was a similar question on this yesterday, but for Java, so I'm interested - what it takes to create a memory leak in C# / .NET (without using unsafe) ?

Community
  • 1
  • 1
Denis Biondic
  • 7,943
  • 5
  • 48
  • 79
  • 1
    Some of the answers in this thread are political, for a real example see here: http://smartbear.com/support/articles/aqtime/net-allocation-profiler/ - "Obviously, this handler is not removed from the given event which results in a leak." – Jeremy Thompson Jul 04 '11 at 06:37

3 Answers3

12

static events; DEADLY, since they never go out of scope.

static event EventHandler Evil;

for(int i = 0 ; i < 1000000 ; i++)
    Evil += delegate {};

The anonymous method is simply a nice-to-have here but are nice because they also are a pig to unsubscribe unless you take a copy into a variable/field and subscribe that.

Technically this isn't actually "leaked", as you can still access them via Evil.GetInvocationList() - however, when used with regular objects this can cause unexpected object lifetimes, i.e.

MyHeavyObject obj = ...
...
SomeType.SomeStaticEvent += obj.SomeMethod;

now the object at obj lives forever. This satisfies enough of a perceived leak IMO, and "my app died a horrible death" is good enough for me ;p

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • but you can still get at them... no? – Adam Ralph Jul 04 '11 at 06:30
  • 1
    Yes, I have had to fix this *once* before... exactly once, because that won't be happening again =) – Ed S. Jul 04 '11 at 06:31
  • @Adam Ralph: All subscribers will be kept around indefinitely (unless unregistered from the event) because the event is static. – Ed S. Jul 04 '11 at 06:31
  • @Adam - added clarification around that – Marc Gravell Jul 04 '11 at 06:33
  • I can see the issue here but can we really call this a memory leak? i.e. does it cause memory to be allocated which can never be freed? – Adam Ralph Jul 04 '11 at 06:34
  • Well, that is sure an interesting situation :) – Denis Biondic Jul 04 '11 at 06:34
  • @Adam Ralph: Yes, it certainly can, because all references to the subscribee that are accessible to the application may go out of scope (ok, just saw the `GetInvocationList()` addition. That's true, but still, you're unlikely to be calling that in your app and this may still crash your program someday =) ). – Ed S. Jul 04 '11 at 06:36
  • 2
    ok, I think this is really just boiling down to a 'what is a memory leak' debate ;-). I can see both points that both @Marc and @Ed are making. I guess I'm being more nitpicky about what I consider to be a true memory leak. I still believe that the situations you are describing a not memory leaks, but rather a way to cause unexpected object life times. Granted that both have the same ultimate effect. – Adam Ralph Jul 04 '11 at 06:44
  • @Adam - which I do indeed note in the answer ;p – Marc Gravell Jul 04 '11 at 06:50
5

When an object subscribes to an event, the object exposing the event maintains a reference to the subscriber (actually, the event, the MultiCastDelegate originally does, but it carries through). This reference will prevent the subscriber from being GC'd if the last reference to it (other than the one maintained by the event) goes out of scope.

The other two answers have this situation completely backward and are incorrect. This is a little tricky to show in a simple example and is typically seen in larger projects, but just remember that a reference to the subscriber is maintained by the MultiCastDelegate (event) and you should be able to think it through.

EDIT: As Marc mentions in his response you could technically get a reference to the "leaked" object via the GetInvocationList() method, but your code is unlikely to be using that and it won't matter when you crash with an OutOfMemoryExcetion.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • very true and I completely I agree - but we should bear in mind that this doesn't answer the question – Adam Ralph Jul 04 '11 at 06:32
  • @Adam Ralph: It doesn't? It describes one way to leak memory. How does that avoid answering the question? – Ed S. Jul 04 '11 at 06:34
  • I don't agree that you are describing a memory leak. A memory leak implies that the GC is broken since it is not freeing up all memory used by unrooted objects. In the situation you describe the references and lifetimes are being maintained correctly and the GC is keeping all the objects alive which it should. – Adam Ralph Jul 04 '11 at 06:40
  • it amuses me slightly that the highest voted answer is really a comment on two of the event-related answers (one of which is now deleted, btw, so the "other two answers" point is slightly confusing, and might be taken to mean my event-related answer, which *isn't* backwards) – Marc Gravell Jul 04 '11 at 06:40
  • @Marc: Well, when I posted this it was the only correct one. My computer shows this posted two minutes before yours, but even if yours was first I didn't see it when I posted. Someone had to get it right damn it! =D I removed the now irrelevant bit. – Ed S. Jul 04 '11 at 06:41
  • @Marc I'm surprised that this question is not yet closed, being an exact duplicate – onof Jul 04 '11 at 06:43
1

Direct memory access is abstracted away from safe managed code. There has to be a call to unsafe code somewhere in order to induce leaking of memory, either in code you write or in a 3rd party resource (possibly within the FCL) with a memory leak bug.

Adam Ralph
  • 29,453
  • 4
  • 60
  • 67