Since .NET has a garbage collector, why do we need finalizers / destructors / dispose-pattern?

If I understand correctly, the .net runtime will always be cleared after me. Therefore, if I create new objects and stop referencing them in my code, the runtime will clear these objects and free up the memory they occupy.

Since this is so, why then some objects must have a destructor or a delete method? Will it be possible to start the environment after them when they will no longer be referenced?

+65
garbage-collection memory-management c # memory
Dec 01 '08 at 18:47
source share
12 answers

Finalizers are needed to guarantee that limited resources exit back to the system, such as file descriptors, sockets, kernel objects, etc. Since the finalizer always works at the end of the life of objects, this is the designated place to release these pens.

The Dispose pattern is used to provide deterministic destruction of resources. Since the garbage collector in .net time mode is not deterministic (which means you can never be sure when the runtime will collect old objects and call their finalizer), a method is needed to ensure a deterministic release of system resources. Therefore, when you correctly implement the Dispose template, you provide a deterministic release of resources, and in cases where the consumer is careless and does not dispose of the object, the finalizer will clear the object.

A simple example of why Dispose is required can be a quick and dirty logging method:

 public void Log(string line) { var sw = new StreamWriter(File.Open( "LogFile.log", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)); sw.WriteLine(line); // Since we don't close the stream the FileStream finalizer will do that for // us but we don't know when that will be and until then the file is locked. } 

In the above example, the file will remain locked until the garbage collector calls the finalizer on the StreamWriter object. This creates a problem because, in the meantime, the method may be called again to write the log, but this time it will fail because the file is still locked.

The correct way is to destroy an object when it is executed with it:

 public void Log(string line) { using (var sw = new StreamWriter(File.Open( "LogFile.log", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))) { sw.WriteLine(line); } // Since we use the using block (which conveniently calls Dispose() for us) // the file well be closed at this point. } 

BTW, technically finalizers and destructors mean the same thing; I prefer to call finalizers of C # destructors, because otherwise they tend to mix people with C ++ destructors, which, unlike C #, are deterministic.

+91
Dec 01 '08 at 18:49
source share

The previous answers are good, but let me emphasize again an important point. In particular, you said that

If I understand correctly, the .net runtime will always be cleared after me.

This is only partially correct. In fact, .NET only offers automatic control for one specific resource : main memory. All other resources need manual cleaning. one)

Oddly enough, the main memory gets a special status in almost all discussions of program resources. Of course, there is a good reason for this - the main memory is often the most scarce resource. But it is worth remembering that there are other types of resources that also need to be managed.




1) A common attempt - to connect the lifetime of other resources with the lifetime of memory locations or identifiers in the code - hence the presence of finalizers.

+19
Dec 01 '08 at 19:08
source share

The garbage collector will only work if the system is not under pressure from the memory, unless it is necessary to free the memory. This means that you can never be sure when the GC will work.

Now imagine that you are connecting to a database. If you let GC clean up after you, you can be connected to the database much longer than necessary, causing a strange load. In this case, you want to implement IDisposable so that the user can call Dispose () or use () to really make sure the connection is closed as soon as possible, without relying on the GC, which can work much later.

As a rule, IDisposable is implemented in any class that works with unmanaged resources.

+9
Dec 01 '08 at 18:51
source share
  • There are things that the garbage collector cannot clean up after you.
  • Even with the things that he can clean, you can help him clean faster.
+4
Dec 01 '08 at 18:55
source share

The real reason is that .net garbage collection is NOT intended to collect unmanaged resources, so cleaning up these resources is still in the hands of the developer. In addition, object finalizers are not called automatically when an object goes out of scope. They are called by the GC at some indefinite time. And when they are called, GC does not start it right away, it waits for the next round to call it, increasing the time for cleaning even more, it is not very good when your objects contain limited unmanaged resources (for example, files or network connections). Enter a one-time use template in which the developer can manually release limited resources at a specific time (when calling the yourobject.Dispose () function or using (...)). Keep in mind that you must call GC.SuppressFinalize (this); in your placement method, to tell the GC that the object was manually deleted and should not be completed. I suggest that you take a look at the book, The Framework Design Guides by K. Kvalina and B. Abrams. He describes the disposable template very well.

Good luck

+2
Dec 01 '08 at 19:01
source share

The simplest explanation:

  • Dispose is designed for deterministic deletion of resources without memory, especially limited resources . For example, a window handle or a database connection.
  • Finalize is for non-deterministic deletion of resources without memory, usually as a callback blocker, if Dispose has not been called.

Some guidelines for implementing the Finalize method:

  • Only implement Finalize for objects requiring completion because there are performance overheads associated with Finalize methods.
  • If you need a Finalize method, consider implementing IDisposable to allow users of your type to avoid the expense of calling the Finalize method.
  • Your Finalize methods should be protected, not public.
  • Your Finalize method should free up any external resources that the type owns, but only those that it owns. It should not refer to other resources.
  • The CLR makes no guarantees regarding the order in which the Finalize method is called. As Daniel notes in his comment, this means that the Finalize method should not have access to any referenced types of participants, if possible, because they can (or may someday) have their own finalizers.
  • Never call the Finalize method directly on any type other than the type of the base type.
  • Try to avoid any unhandled exceptions in your Finalize method, as this will terminate your process (in version 2.0 or higher).
  • Avoid doing any long-term task in your Finalizer method, as this blocks the Finalizer thread and prevents other Finalizer methods from executing.

Some guidelines for implementing the Dispose method:

  • Implement a dispose design pattern for a type that encapsulates resources that clearly need to be freed.
  • Implement the dispose design template on a base type that has one or more derived types that are stored on resources, even if the base type does not.
  • After Dispose is called on the instance, prevent the Finalize method from starting by calling the GC.SuppressFinalize method. The only exception to this rule is a rare situation in which work must be performed in Finalize, which is not covered by Dispose.
  • Do not assume that Dispose will be invoked. Type unmanaged resources must also be released in the Finalize method in case Dispose is not called.
  • Throw an ObjectDisposedException from the instance methods of this type (except Dispose) when the resources are already set. This rule does not apply to the Dispose method, because it must be called multiple times without throwing an exception.
  • Distribute Dispose calls through a hierarchy of base types. The Dispose method must release all resources held by this object and any object belonging to this object.
  • You should not consider the possibility of using an object after calling the Dispose method. Re-creating an object that has already been deleted is a complex template to implement.
  • Allow the Dispose method to be called more than once without exception. After the first call, the method should not do anything.
+2
Dec 01 '08 at 19:24
source share

Objects that need descriptors and deletion methods are the use of resources without control. Therefore, the garbage collector cannot clean up these resources, and you need to do it yourself.

See the MSDN documentation for IDisposable; http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

The example uses an unmanaged handler, IntPr.

+1
Dec 01 '08 at 18:50
source share

Some objects may need to clean low-level items. For example, hardware that needs to be shut down, etc.

0
Dec 01 '08 at 18:49
source share

Mostly for uncontrolled code and interaction with unmanaged code. Pure managed code never needs a finalizer. Disposable on the other hand is just a handy template that will make something free when you are done with it.

0
Dec 01 '08 at 18:50
source share

The .NET garbage collector knows how to process managed objects in the .NET runtime. But the Dispose (IDisposable) pattern is mainly used for unmanaged objects that the application uses.

In other words, the .NET runtime doesn’t necessarily know how to handle each type of device or process it (closing network connections, file descriptors, graphics devices, etc.), so using IDisposable provides a way to say “let me implement some cleaning of my own "in type. Upon seeing this implementation, the garbage collector can call Dispose () and ensure that things are cleaned up outside the managed heap.

0
Dec 01 '08 at 18:51
source share

There are several (very few) cases where it may be necessary to perform a certain action, when a clean managed object is no longer used, I can’t come up with an example from the top of my head, but I have seen a couple of legitimate goals over the years. But the main reason is to clean up any unmanaged resources that the object can use.

So, in the general case, you do not need to use the Dispose / Finalize template if you are not using unmanaged resources.

0
Dec 01 '08 at 18:53
source share

Because the garbage collector cannot collect what the managed environment could not allocate. Therefore, any unmanaged API call that results in memory allocation must be collected in the old fashioned way.

0
Dec 01 '08 at 18:56
source share



All Articles