3

A friend of mine told me that .NET Framework is memory hungry and he gave me an example that if I make an application (in .NET web forms) which will take 20 mb of your RAM, it will be actually wasting 1.5 MB

This means that it will leak 15 mb for 200 MB application which is way too much.

Is it true? Can anyone provide me any links which describes it?

11
  • 10
    7.5% overhead in memory consumption sounds like a small price for a state-of-the-art JIT compiler, a sophisticated GC and a various high-level frameworks. Nobody leaks memory on purpose, rest assured that it's a necessary price all the comfort the platform gives you, and something similar will exist for every technolofy save natively-compiled code without runtime. And you don't want to program in the languages that provide that.
    – user7043
    Jun 5, 2011 at 15:20
  • 7
    "means that it will leak 15 mb for 200 MB": it doesn't mean that. Some of that will be fixed overheads whatever the application's size. But then the base statement "1.5MB is wasted": citation needed.
    – Richard
    Jun 5, 2011 at 15:41
  • 5
    I think the better question might be to have your friend document his statement.
    – Walter
    Jun 5, 2011 at 15:46
  • 2
    @delnan: Why doesn't the OP want to program in a native code language? I use Delphi and it's every bit as productive and easy to use as anything from the .NET world, without all the overhead of managed code. Jun 5, 2011 at 16:16
  • 1
    we need some actual tests and numbers here instead of opinions, someone cared to do that?
    – Lie Ryan
    Jun 5, 2011 at 19:21

3 Answers 3

13

.net utilizes a managed heap that exists in conjugation with the os memory functions built into windows. While the initial start up cost of the runtime can make the system look very memory intensive for large scale programs I have found it to not be that significant. You need to remember that the managed memory access is tested by thousands of developers every year and on average will beat your best efforts at memory management for any program of significant scope.

3
  • +1 I remember reading quite a bit that the .NET garbage collection inside the CLR is actually pretty good.
    – Jon
    Jun 5, 2011 at 15:29
  • 3
    @Jon: that would be Microsoft documentation, they're not going to say it's bad now are they! (well, not until the next big thing come along and then they'll slag it off like they did with reference counting :) )
    – gbjbaanb
    Jun 5, 2011 at 18:47
  • @gbjbaanb Perhaps there or from a book published by Microsoft Press :p
    – Jon
    Jun 5, 2011 at 19:05
7

I doubt that there really is a direct answer to this.

There are two problems to consider. First, with garbage collection, you generally get a fairly direct trade-off between speed and memory consumption. If you run the garbage collector more often, you reduce memory consumption at the expense of using more CPU time. Running the garbage collector less often improves speed at the expense of consuming more memory. Testing has shown that garbage collection can provide the same speed as manual memory management, at the expense of consuming roughly six times as much memory1.

The second basic point is generality versus specificity. On one hand, the people working on .NET are (beyond a doubt) very smart, and work very hard at making it work well. For the most part, they succeed. On the other hand, .NET gets used for a wide variety of purposes across an even wider range of hardware. That has a large effect on the design goal. In particular, the emphasis is almost entirely to avoid really bad performance under any conditions, not necessarily to provide great performance under your conditions.

As far as the specific allegation of 20 MB leading to 1.5 MB of "waste", I doubt that anybody can really address it directly -- it's impossible to even be sure what he was trying to say, not to mention trying to say anything about whether (and if to so what degree and/or under what circumstances) it might be accurate. It's certainly not true that memory usage is necessarily linear, so even if 20 MB of use lead to 1.5 MB of waste, that wouldn't imply 15 MB of waste for 200 MB of use. Depending on what he was talking about, it might remain at 1.5 MB regardless, or it might scale sub-linearly (or, possibly, super-linearly).


1Those specific tests were run with Java, but .NET is sufficiently similar that while the number might change a little, I wouldn't expect the difference to be huge. For that matter, I know of at least three different garbage collection methods used in different JVMs, so the exact number probably varies for different Java implementations.

2
  • Garbage collection is often the most efficient way of handling owner-less immutable objects that are widely shared between threads in a multi-processor system. Reference counting isn't too bad in a single-processor system, but if multiple threads may be creating and destroying references to an object, updates to the reference counts must be coordinated among all processors. That's a MAJOR speed hit, which is avoided when using GC. That having been said, I wish a framework would recognize the usefulness of both strongly-owned and owner-less objects.
    – supercat
    Oct 27, 2012 at 18:17
  • In Java and frameworks derived from it, there is no concept of object ownership; an objects exist as long as a reference exists. This is unfortunate, both because bug-free programming generally requires that a programmer know what objects "own" the states of what other objects, even if the computer doesn't, and also because object will sometimes hold references to objects in which they have no particular interest, for the purpose of doing things on the latter objects' behalf. Although WeakReference can be helpful in handling the latter situation, it has its limits.
    – supercat
    Oct 27, 2012 at 18:23
3

Although most of my experience is with non-GC programming, I don't really believe either GC or non-GC is universally superior.

What I will say, however, is that trading memory overheads for speed, or for other resources, is quite common - even for non-GC languages.

Some examples...

A naive resizeable array grows by fixed increments. When inserting a large number of items, this results in O(n^2) performance because of the O(n) reallocate-and-copy operations on the array. A faster alternative is "array doubling" - more accurately, growing by a fixed factor. This gives amortized O(n) performance for a long sequence of inserts. The cost is that, instead of having a fixed maximum memory overhead, the maximum overhead is proportional to the number of items in the array.

EDIT - silly mistake above - array gives amortized O(1) for each insert, but strictly O(n) for a series of n inserts, due to how "amortized" is defined.

Array doubling is not only applied to simple resizable vector/array types, but also to types that have resizeable arrays underlying them - the most obvious being hash tables. Without this proportional memory overhead, the amortised O(1) insert/delete times for resizeable hashtables cannot be achieved. This applies irrespective of whether garbage collection is used.

Similarly, with B trees and B+ trees (commonly used for database indexes), each node is guaranteed to be at least half full - with the exception of the root, which may even be completely empty. These data structures are more likely used on disk than in main memory, but either way they have an expected memory/storage overhead that grows in proportion with the number of items.

With garbage collection algorithms, there are also trade-offs between memory and performance. This can be seen as an extra layer on top of the data structures in some cases, adding an extra layer of waste, but this isn't a general rule - I don't know what weight to put on each two cases.

In unmanaged languages, you need some other mechanism to keep track of memory that needs to be freed anyway. Sometimes, that comes pretty much for free in the data structure itself - e.g. in a binary tree, you need the child links irrespective of whether you use them for a delete-all-items operation or not. But other times that too can involve a tradeoff between extra memory overheads and performance. For example, "memory pools" are often used to trade memory overheads (the whole pool remains allocated, even though relatively few items within the pool are in use at any particular time) for a faster and more convenient free of all items at once.

My basic point is, I guess, a variation on "avoid premature optimisation". Don't worry too much about memory overheads unless you know they will cause a problem. And be aware that when you reduce memory overheads, you are likely to pay with increases to other overheads - so do before and after measurements of more than just memory usage.

It may seem like it's too late to think of changing language when you find a problem with garbage collection memory overheads, but there are things you can do without re-writing your whole system. For example, when coding in C# for .NET, one option is to reimplement a critical data structure using some unmanaged C++.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.