1

I was wondering what are the best practices when creating objects, performing LINQ in C#. For instance, I realize that when I open up a connection using LINQ I should be putting the model object into a using statement like this:

using(var ctx = new mymodel())
{

}

Now, what about the objects that are EF classes?

They do not implement IDisposable interface thus I can't do something like this when creating an object like this for example:

using(var user = new Users())
{

}

But when an action is called like this:

public ActionResult InsertUser()
{

    var user = new Users();

}

I have no clear picture what happens with this object once the insert into the db is finished. Does this object stays allocated in memory or it gets released? If not, what are best practices to release memory once they aren't needed anymore..?

On the other there are static variables as well...

So to sum things up, my questions are:

  • what are best practices to release memory when creating instances of an object of a class?

  • Is implementation of IDisposable interface on every class that I have good choice?

  • When a static variable is created in .NET MVC, what is the best way to release memory taken by this kind of variables?

  • Same question goes for Session object?

P.S. Guys, I'd really appreciate if all of you that are reading this to post your opinion or post some useful links for some documentations/blog posts so that I can expand my horizons =)

User987
  • 3,663
  • 15
  • 54
  • 115
  • 1
    Do you have a problem with memory consumption? – trailmax Feb 06 '17 at 18:25
  • 1
    Objects are collected when they go out of scope. If no active code regions reference the object or an object tree that indirectly references it, it will be collected. You only need to implement `IDisposable` on classes that have unmanaged resources it needs to clean up. –  Feb 06 '17 at 18:25
  • @trailmax yes that's exactly the problem, I don't know where it's coming from but I need to figure things out to maximize efficiency of my code.. =) – User987 Feb 06 '17 at 18:26
  • 2
    This is an example of premature optimization. Are you actually having performance issues? –  Feb 06 '17 at 18:27
  • @Amy You mean they are collected by garbage collector ? – User987 Feb 06 '17 at 18:27
  • @Amy I don't know how would you define performance issue but for example I noticed on my server that the proecss IISWorker takes up to 1.2 GB of RAM... That concerned me a lot so that's the reason I'm asking this question. Could this be related to the fact that 100+ people are using the application at the same time ? – User987 Feb 06 '17 at 18:29
  • 1
    Yes I would say that's definitely related. And yes, I mean they are collected by the garbage collector. –  Feb 06 '17 at 18:31
  • @Amy Whew ur reply got me less worried now, that's a few grey hairs less =))... Well what about the code efficiency... Are there any points I should look for when working with C# and generally LINQ / EF ? The whole point of my question is to widen my perspective on code efficiency... =) – User987 Feb 06 '17 at 18:33
  • P.S. Amy, does the garbage collector empties out memory from objects of custom classes that I made, and that don't implement IDisposable interface? – User987 Feb 06 '17 at 18:35
  • GC collects all objects. Even if class implements IDisposable, instance of this class will **not** be collected (so memory will not be reclaimed) when you call Dispose. You are using language with garbage collection so in general you should stop worrying about memory management (except when you work with unmanaged resources and in some specific cases). – Evk Feb 06 '17 at 18:39
  • @Evk Could you be more specific when u say "unmanaged resources" ... Could you write an answer so that I can see ur full reply ? =) I'm tryna to expand my horizons and understand how c# in general works under the hood.. – User987 Feb 06 '17 at 18:41
  • 3
    As always, **read the documentation** on the garbage collector. It will tell you what "unmanaged resources" are. Come back here when you have more specific questions. –  Feb 06 '17 at 18:45

3 Answers3

4

Before you do any performance tweaks I highly recommend to run a memory profiler (for example JetBrains dotMemory, but there are others) and find out the actual source of the problem. Without information from profiler, your optimisations will be like sticking your finger at a sky and shouting "Rainbow!" i.e. useless at best, harmful at worst.

Also after identifying issues with profiler, but before starting changing your code, I recommend reading about how Garbage Collection works in .Net. Here are some references to get you started:

  1. MSDN Garbage Collection
  2. MSDN Garbage Collector Basics and Performance Hints
  3. .Net Garbage Collection in depth

Here are some links to answer your questions:

Community
  • 1
  • 1
trailmax
  • 34,305
  • 22
  • 140
  • 234
2

In response to comment.

When you create regular .NET object, .NET runtime knows everything about it, because runtime created it. It knows where in memory it's located, when it is no longer needed and so on. When it is no longer needed - runtime will reclaim its memory. That is managed (by runtime) object. You should not care about memory management for such objects.

Now take for example file handle. When you open file in .NET, it will delegate this operation to OS (for example, Windows). This resource is not managed by runtime, it is managed by OS. So, it is unmanaged resource. So author of .NET library code which works with files (I mean person who created FileStream and similar classes, not uses them) should manually write code to release such resource (close file handle in this case). By convention, author will use IDisposable.Dispose method for code that releases such resources AND ensures that when underlying object (like FileStream) will be collected by GC - unmanaged resources will also be released. So even if you forget to call Dispose - file handle will be closed when GC collects FileStream (not that it will happen not magically but because code author explicitly made it happen like this). But that might happen any time in the future, you don't want to leave file handle open for undetermined time - so you always call Dispose yourself when you are done with IDisposable object.

The same applies to most unmanaged resources. For example, database connection is managed by database, and you don't want to leave database connection open for undetermined time, so you call Dispose and explicitly notify database to close it (and even if you don't call it - author of .NET database code took care to do that when object is collected). EF context wraps database connection, so it also implements IDisposable. If you don't want to leave connection open until context will be collected (and you sure don't want that) - you call Dispose yourself.

Or suppose you write your own code to work with images using ImageMagick. That is C library, so runtime has no idea about its inner workings. You ask library to allocate memory for your image, but .NET cannot reclaim such memory - it does not manage it, it is managed by ImageMagick C library. So you implement IDisposable and tell ImageMagick to release memory in that method.

Evk
  • 98,527
  • 8
  • 141
  • 191
0

In the case of var user = new Users(); which does not implement IDisposable, and any object for that matter which is not disposed, will only be guaranteed to exist where there is an active reference to this object; after which it will qualify for disposal the next time the Garbage Collector (GC) tries to free up memory.

In your example above, as soon as this leaves the method InsertUser() it will no longer have any references pointing to it, and therefore will be up for garbage collection.

If however a reference exists, such as in the following code, the object will not be disposed until the reference is cleared, or the containing class is disposed.

private User _insertedUser;

public ActionResult InsertUser()
{

    _insertedUser = new Users();

}

The garbage collector fires when the application needs to release some memory. When it fires, it performs several sweeps on objects within memory to tell if any references exist. It first scans every object which has been newly created since the last time the GC was called. Objects which survive this sweep are promoted a generation. If after the sweep more memory is still required, then a 2nd generation sweep is performed. This will scan every object which has survived a single garbage collection to see if it can now be freed. Again if an object survives, it moves up another generation, with 3 generation sweeps in total.

This method helps the GC perform memory management while limiting the high costs involved (newer objects are more likely to be available for release). As GC has a high cost associated to it, it's better if objects are disposed of through user's code to help limit the number of times the GC is called.

tldr;

  • Dispose objects if they implement IDisposable; an easy way is to surround it by a 'using'.
  • If an object cannot be disposed, and it is no longer required, make sure all references to the object is cleared (especially references outside of a method which the object was created). This enables the GC to release it from memory.
Radderz
  • 2,770
  • 4
  • 28
  • 40