8

In C++ it is easily possible to have a permanent memory leak - just allocate memory and don't release it:

new char; //permanent memory leak guaranteed

and that memory stays allocated for the lifetime of the heap (usually the same as program runtime duration).

Is the same (a case that will lead to a specific unreferenced object never been released while memory management mechanisms are working properly) possible in a C# program?

I've carefully read this question and answers to it and it mentions some cases which lead to getting higher memory consumption than expected or IMO rather extreme cases like deadlocking the finalizer thread, but can a permanent leak be formed in a C# program with normally functioning memory management?

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979

7 Answers7

25

It depends on how you define a memory leak. In an unmanaged language, we typically think of a memory leak as a situation where memory has been allocated, and no references to it exist, so we are unable to free it.

That kind of leaks are pretty much impossible to create in .NET (unless you call out into unmanaged code, or unless there's a bug in the runtime).

However, you can get another "weaker" form of leaks: when a reference to the memory does exist (so it is still possible to find and reset the reference, allowing the GC to free the memory normally), but you thought it didn't, so you assumed the object being referenced would get GC'ed. That can easily lead to unbounded growth in memory consumption, as you're piling up references to objects that are no longer used, but which can't be garbage collected because they're still referenced somewhere in your app.

So what is typically considered a memory leak in .NET is simply a situation where you forgot that you have a reference to an object (for example because you failed to unsubscribe from an event). But the reference exists, and if you remember about it, you can clear it and the leak will go away.

jalf
  • 243,077
  • 51
  • 345
  • 550
  • 2
    If a program keeps throwing stuff into a collection which it never bothers to empty because the programmer forgot to do so, I wouldn't really consider that a memory leak. On the other hand, if a reference to an object exists in a form whose removal would require information that no longer exists, that would be a memory leak. For example, if an event subscriber is abandoned, unless the publisher uses complicated trickery to emulate weak events, there may be no way for the event to get unsubscribed as long as the publisher is in scope. – supercat Jun 21 '11 at 22:54
2

You can write unmanaged code in .NET if you wish, you have enclose your block of code with unsafe keyword, so if you are writing unsafe code are you not back to the problem of managing memory by yourself and if not get a memory leak?

Kiran Bheemarti
  • 1,439
  • 2
  • 12
  • 14
1

It's not exactly a memory leak, but if you're communicating with hardware drivers directly (i.e. not through a properly-written .net extension of a set of drivers) then it's fairly possible to put the hardware into a state where, although there may or may not be an actual memory leak in your code, you can no longer access the hardware without rebooting it or the PC...

Not sure if this is a useful answer to your question, but I felt it was worth mentioning.

Frosty840
  • 7,965
  • 12
  • 50
  • 86
1

GC usually delay the collection of unreachable memory to some later time when an analysis of the references show that the memory is unreachable. (In some restricted cases, the compiler may help the GC and warn it that a memory zone is unreachable when it become so.)

Depending on the GC algorithm, unreachable memory is detected as soon as a collection cycle is ran, or it may stay undetected for a certain number of collection cycles (generational GC show this behavior for instance). Some techniques even have blind spots which are never collected (use of reference counted pointer for instance) -- some deny them the name of GC algorithm, they are probably unsuitable in general purpose context.

Proving that a specific zone will be reclaimed will depend on the algorithm and on the memory allocation pattern. For simple algorithm like mark and sweep, it is easy to give a bound (says till the next collection cycle), for more complex algorithms the matter is more complex (under a scheme which use a dynamic number of generations, the conditions in which a full collection is done are not meaningful to someone not familiar with the detail of the algorithm and the precise heuristics used)

AProgrammer
  • 51,233
  • 8
  • 91
  • 143
0

A simple answer is that classic memory leaks are impossible in GC environments, as classically a memory leak is leaked because, as an unreferenced block theres no way for the software to find it to clean it up.

On the other hand, a memory leak is any situation where the memory usage of a program has unbounded growth. This definition is useful when analyzing how software might fail when run as a service (where services are expected to run, perhaps for months at a time).

As such, any growable data structure that continues to hold onto references onto unneeded objects could cause service software to effectively fail because of address space exhaustion.

Chris Becke
  • 34,244
  • 12
  • 79
  • 148
  • 1
    `a memory leak is any situation where the memory usage of a program has unbounded growth` This is wrong. The question is not whether the leak is bounded or not. `Leak is when memory that can be released does not get released.` – Aliostad Apr 15 '11 at 10:42
  • I have a tap which leaks whenever I use it. So does it leak or not? – Aliostad Apr 15 '11 at 10:45
  • @Aliostad: but your tap *keeps* leaking as long as you use it. So it is unbounded. Anyway, you use a different definition of "memory leak" than @Chris. Why is yours right and his one wrong? That seems pretty subjective to me. – jalf Apr 15 '11 at 10:52
  • Well because the example in the question is not unbounded either. If in C++ I create `char* ch = new char[200];` unless I `delete` it, the memory has **leaked**. The question is not boundedness. – Aliostad Apr 15 '11 at 10:55
  • 2
    @Aliostad: The question of whether it's bounded or not depends upon whether repeating the same action would result in additional memory being lost. I would not regard code like "{static char *foo; if (!foo) foo=new char[200];}" as leaking, since one could call the code a million times and only lose a constant amount of storage. If 'foo' weren't static, though, I'd consider the code leaky. – supercat May 10 '11 at 19:25
0

Easiest memory leak:

public static class StaticStuff
{
    public static event Action SomeStaticEvent;
}

public class Listener
{
   public Listener() {
      StaticStuff.SomeStaticEvent+=DoSomething;
   }
   void DoSomething() {}
}

instances of Listener will never be collected.

TDaver
  • 7,164
  • 5
  • 47
  • 94
  • This relies on a `static` member variable that will in fact reference those objects. – sharptooth Apr 15 '11 at 10:44
  • @TDaver: exactly why it doesn't answer the question as stated. Please read it again carefully. – R. Martinho Fernandes Apr 15 '11 at 11:51
  • 1
    @Martinho Fernandes: Event-listeners that are abandoned without being unsubscribed are a very common real-world source of leaks. If an unbounded number of event listeners can be created and abandoned, and if none of them will ever be unsubscribed, they will force an unbounded amount of memory to be held uselessly. – supercat May 10 '11 at 19:27
  • @Martinho Fernandes: This scenario is hardly far-fetched. Some implementations of IEnumerable use events to notify numerators if the underlying collection changes. It may be entirely reasonable to enumerate a collection millions times during its lifetime; if each attempted enumeration subscribes an event handler, but nobody ever calls Dispose on the enumerators, none of the enumerators will ever get garbage-collected unless the designer implemented some sort of 'weak event' pattern. – supercat May 10 '11 at 19:32
  • @supercat: yes, abandoning event handlers is a source of "memory leaks". But the question asked about "a case that will lead to a specific **unreferenced** object never been released while memory management mechanisms are working properly" (emphasis mine). This is just a case of references that are held forever, not unreferenced but not collected objects. – R. Martinho Fernandes May 10 '11 at 22:38
  • @Martinho Fernandes: A dangling event handler may be referenced in a way that the system can track down, but that doesn't mean that it's referenced in any way that would enable an application to clean it up. – supercat May 10 '11 at 22:45
  • @supercat: it doesn't let *your* code clean it up. That's just because the reference is kept in a private field. But there is still a reference there. – R. Martinho Fernandes May 10 '11 at 22:52
  • 1
    @Martinho Fernandes: The (system agnostic) essence of a memory leak is that memory is that one entity holds memory on behalf of another entity which it wrongly believes still needs it and wrongly expects to be told when it's no longer needed. Sounds like what happens with dangling event subscriptions. – supercat May 11 '11 at 00:39
  • @supercat: That's true. But that's actually the answer to a different question. – R. Martinho Fernandes May 11 '11 at 00:47
  • 2
    @Martinho Fernandes: From a practical perspective, if some memory is going to be held forever by some entity on behalf of some other entity which has abandoned it, the memory is leaked. I would say that many dangling event scenarios fit that description just fine. – supercat May 11 '11 at 01:29
-1

If we define memory leak as a condition where a memory that can be used for creating objects, cannot be used or a memory that can be released does not then

Memory leaks can happen in:

  • Events in WPF where weak events need to be used. This especially can happens in Attached Properties.
  • Large objects

Large Object Heap Fragmentation

http://msdn.microsoft.com/en-us/magazine/cc534993.aspx

Community
  • 1
  • 1
Aliostad
  • 80,612
  • 21
  • 160
  • 208
  • 4
    I always believed that GC can detect circular references and that's it's huge advantage over smart pointers. – sharptooth Apr 15 '11 at 10:29
  • I was also under that impression. Given that an (old) circular reference is not rooted, GC picks it up. – spender Apr 15 '11 at 10:31
  • Actually the GC handles very well the circular references and it should not lead to memory leaks. – Dumitrescu Bogdan Apr 15 '11 at 10:32
  • Circular references only defeat some GC strategies, like reference counting. – R. Martinho Fernandes Apr 15 '11 at 10:33
  • It's fairly easy to test this, simply create an A and a B class, where A references B and B references A. Run a non-exiting loop which creates these circular-referencing objects. You should be able to open Task Manager and watch the memory use build up and be cleared every couple of seconds. I remember watching memory use doing this, for some reason, but I can't remember if I was testing circular references or not... – Frosty840 Apr 15 '11 at 10:34
  • Thanks everyone. Corrected. I need to investigate a bit more. – Aliostad Apr 15 '11 at 10:35
  • @Frosty840, no need to infer from memory usage. Write a finalizer method for the objects that refer to each other that reports when it is called, drop external references then call GC.Collect – spender Apr 15 '11 at 10:37
  • 1
    -1 for being incorrect. None of the 3 points corresponds to any kind of memory "leak". – Chris Becke Apr 15 '11 at 10:38
  • The WPF example can be generalized to "inadvertedly holding references to unused objects." And that is kind of stretching the definition. – R. Martinho Fernandes Apr 15 '11 at 10:40
  • 1
    @spender: Yeah, but it's fun to watch the memory usage meter bounce up and down. I am a simple man, with simple pleasures. :D – Frosty840 Apr 15 '11 at 10:40