C # Memory Model

Source: Internet
Author: User

, 1.. Net Type and memory allocation 2. Working Principle of GC Garbage Collector 3. What are unmanaged resources 4. How to effectively release object Resources. Summary: now we will start learning this section.

1.. Net Type and Memory Allocation

All types in. NET are (directly or indirectly) derived from the system. Object type.

The type in CTS is divided into two categories: reference type (managed type), which is allocated to the memory stack and value type ). Value types are allocated on the stack.

The value type is in the stack. When it comes out first, the Life Sequence of the value type variable is sequential. This ensures that the value type variable will release resources before the scope is released. It is simpler and more efficient than the reference type. The stack allocates memory from the high address to the low address.

The reference type is assigned to the managed heap, and a variable is declared to be saved on the stack. when an object is created using new, the object address is stored in the variable. Instead, the managed heap allocates memory from the low address to the high address,

2. Working Principle of GC Garbage Collector

When dataset expires, the destruction object is not displayed, and the object on the stack continues to exist, waiting for GC collection.

It is recommended but not necessary for the garbage collector to support the aging of objects through generational support. A generation is a unit of relatively old objects in the memory. Object

Code or age ID object belongs to that generation. In the life cycle of an application, objects created more recently belong to the newer generation, and objects created earlier have

The lower part code. The object code in the latest generation is 0.

When creating a new object, you must first search for the idle linked list, find the most suitable memory block, allocate, adjust the memory block linked list, and merge fragments. The new operation can be completed almost at O (1) time, adding 1 to the heap top pointer. The working principle is: when there is not enough space on the hosting stack, or the space of generator 0 is full, GC runs and starts to recycle the memory. At the beginning of garbage collection, GC compresses and adjusts the heap memory, and the objects are concentrated on the top. GC takes a certain amount of CPU time when scanning garbage. The original GC algorithm is actually scanning the entire heap, with low efficiency. The current GC divides the objects in the heap into three generations, and the last generation that enters the heap is generation 0, followed by generation 1, generation2. the first GC only scans 0th generations. If the collected space is sufficient, you do not need to scan other generation objects. Therefore, GC creates objects more efficiently than C ++, and does not need to scan all heap spaces. It uses a scan policy and memory management policy to improve performance, which is enough to compensate for the CPU time occupied by GC.

3. What are unmanaged resources?

A common unmanaged resource is the object that wraps operating system resources, such as files, windows, or network connections. For such resources, although the garbage collector can track the lifetime of objects that encapsulate unmanaged resources, but it knows how to clear these resources. Fortunately, the finalize () method provided by. NET framework allows the Garbage Collector to clear unmanaged resources properly before recycling such resources. The following lists some common unmanaged resources: paint brushes, stream objects, component objects, and other resources (such as object, odbcdatareader, oledbdatareader, pen, RegEx, socket, streamwriter, applicationcontext, and brush,

Component, componentdesigner, container, context, cursor, filestream,

Font, icon, image, matrix, timer, tooltip ). (Refer to msdn)

4. How to effectively release unmanaged resources.

GC cannot manage unmanaged resources. How can I release an unmanaged resource ?. NET provides two methods:

(1) destructor: When the Garbage Collector recycles resources of an unmanaged object, it will call the finalize () method of the object to clear the resource, however, due to restrictions of GC rules, GC calls the Finalize method of the object. The resource is not released for the first time and the object is deleted after the second call.

(2) inherit the idisposable interface and implement the dispose () method. The idisposable interface defines a mode (with language-level support), which provides a definite mechanism for releasing unmanaged resources, avoid the problems inherent in the Destructor related to the garbage collector.

To better understand the garbage collection mechanism, I wrote some code and added detailed comments. Define a single class frankclasswithdispose (inherited interface idisposable), frankclassnofinalize (no Terminator), and frankclasswithdestructor (defined destructor ).

The Code is as follows:

Code
1 using system;
2 using system. Collections. Generic;
3 using system. text;
4 using system. Data;
5 using system. Data. ODBC;
6 using system. drawing;
7 // coded by Frank Xu Lei 18/2/2009
8 // study the. NET Memory Management
9 // Garbage Collector garbage collector. The managed resources can be reclaimed as required by the policy,
10 // But GC does not know how to manage unmanaged resources. Such as network connection, database connection, paint brush, components, etc.
11 // two mechanisms are used to release unmanaged resources. Destructor and idispose APIs
12 // com reference count
13 // C ++ manual management, new Delete
14 // VB Automatic Management
15 namespace memorymanagement
16 {
17 // inherit the idisposable interface to implement the dispose method and release frankclassdispose instance Resources
18 public class frankclasswithdispose: idisposable
19 {
20 private odbcconnection _ odbcconnection = NULL;
21
22 // Constructor
23 public frankclasswithdispose ()
24 {
25 if (_ odbcconnection = NULL)
26 _ odbcconnection = new odbcconnection ();
27 console. writeline ("frankclasswithdispose has been created ");
28}
29 // Test Method
30 public void dosomething ()
31 {
32
33/*** // code here to do something
34 return;
35}
36 // implement dispose to release resources used by this class
37 public void dispose ()
38 {
39 if (_ odbcconnection! = NULL)
40_odbcconnection. Dispose ();
41 console. writeline ("frankclasswithdispose has been disposed ");
42}
43}
44 // finalize is not implemented. Wait for the GC to recycle the frankclassfinalize instance resources and directly recycle the instance resources when the GC is running.
45 public class frankclassnofinalize
46 {
47 private odbcconnection _ odbcconnection = NULL;
48 // Constructor
49 public frankclassnofinalize ()
50 {
51 if (_ odbcconnection = NULL)
52 _ odbcconnection = new odbcconnection ();
53 console. writeline ("frankclassnofinalize has been created ");
54}
55 // Test Method
56 public void dosomething ()
57 {
58
59 // GC. Collect ();
60/*** // code here to do something
61 return;
62}
63}
64 // implement the destructor, compile it as the Finalize method, and call the object's destructor
65 // when GC is running, it is called twice. Resources are not released for the first time, and resources are not released for the second time.
66 // frankclassdestructor instance Resource
67 // CLR uses an independent thread to execute the Finalize method of the object. frequent calls may degrade the performance.
68 public class frankclasswithdestructor
69 {
70 Private odbcconnection _ odbcconnection = NULL;
71 // Constructor
72 public frankclasswithdestructor ()
73 {
74 if (_ odbcconnection = NULL)
75_odbcconnection = new odbcconnection ();
76 console. writeline ("frankclasswithdestructor has been created ");
77}
78 // Test Method
79 public void dosomething ()
80 {
81/*** // code here to do something
82
83 return;
84}
85 // destructor to release unmanaged Resources
86 ~ Frankclasswithdestructor ()
87 {
88 If (_ odbcconnection! = NULL)
89 _ odbcconnection. Dispose ();
90 console. writeline ("frankclasswithdestructor has been disposed ");
91}
92}
93}
94
The instance uses an unmanaged object odbcconnection. A simple test is performed on the created client. The client code is as follows:

Code
1 using system;
2 using system. Collections. Generic;
3 using system. text;
4 using system. Data;
5 using memorymanagement;
6 // coded by Frank Xu Lei 18/2/2009
7 // study the. NET Memory Management
8 // test the unmanaged objects reclaimed.
9 // test and compare unmanaged code
10 // The managed code, GC can be more self-collected, idisposable, call the dispose () method, and actively release.
11 namespace memorymanagementclient
12 {
13 class Program
14 {
15 static void main (string [] ARGs)
16 {
17
18 /**//////////////////////////////////// /// // (1) //////////////////////////////////////// ////
19 // call the dispose () method and release it. Resource, flexible
20 frankclasswithdispose _ frankclasswithdispose = NULL;
21 try
22 {
23 _ frankclasswithdispose = new frankclasswithdispose ();
24 _ frankclasswithdispose. dosomething ();
25
26}
27 finally
28 {
29 If (_ frankclasswithdispose! = NULL)
30_frankclasswithdispose. Dispose ();
31 // console. writeline ("The frankclasswithdispose instance has been released ");
32}
33
34 /**//////////////////////////////////// /// // (2) //////////////////////////////////////// //////
35 // you can use the using statement to create an unmanaged object.
36 using (frankclasswithdispose _ frankclasswithdispose2 = new frankclasswithdispose ())
37 {
38 // _ frankclasswithdispose2.dosomething ();
39}
40
41 /**//////////////////////////////////// /// // (3) //////////////////////////////////////// ////
42 // resources are released once when the garbage collector is running
43 frankclassnofinalize _ frankclassnofinalize = new frankclassnofinalize ();
44 _ frankclassnofinalize. dosomething ();
45
46 /**//////////////////////////////////// /// // (4) //////////////////////////////////////// //////
47 // resources can be released twice when the garbage collector is running
48 frankclasswithdestructor _ frankclasswithdestructor = new frankclasswithdestructor ();
49 _ frankclasswithdestructor. dosomething ();
50 /**//////////////////////////////////// /// // (5) //////////////////////////////////////// /////
51 // you cannot use the using statement to create an object because it does not implement the idispose interface.
52 // using (frankclasswithdestructor _ frankclasswithdestructor2 = new frankclasswithdestructor ())
53 //{
54 // _ frankclasswithdestructor2.dosomething ();
55 //}
56
57 /**//////////////////////////////////// //////////////////////////////////////// ///////////
58 // For debug
59 console. writeline ("press any key to continue ");
60 console. Readline ();
61
62
63}
64}
65}
66
In some cases, resources must be released at a specific time. The class can implement the idisposable interface for executing resource management and clearing the task method idisposable. dispose.
If the caller needs to call the dispose method to clear the object, the class must implement the dispose method as part of the contract. The garbage collector is not called by default.
The dispose method. However, to implement the dispose method, you can call the methods in GC to regulate the final behavior of the garbage collector.

It is worth mentioning that the dispose () method can be called to actively release resources and be flexible. You can use the using statement to create an unmanaged object. Before the method is executed, it will call
The dispose () method releases resources. The effects of the Code on both ends are the same. You can view the compiled Il.

Code
1. Try
2 {
3 il_0003: NOP
4 il_0004: newobj instance void [memorymanagement] memorymanagement. frankclasswithdispose:. ctor ()
5 il_0009: stloc.0
6 il_000a: ldloc.0
7 il_000b: callvirt instance void [memorymanagement] memorymanagement. frankclasswithdispose: dosomething ()
8 il_0010: NOP
9 il_0011: NOP
10 il_0012: Leave. s il_0028
11} // end. Try
12 finally
13 {
14 il_0014: NOP
15 il_0015: ldloc.0
16 il_0016: ldnull
17 il_0017: CEQ
18 il_0019: stloc. s CS $4 $0000
19 il_001b: ldloc. s CS $4 $0000
20 il_001d: brtrue. s il_0026
21 il_001f: ldloc.0
22 il_0020: callvirt instance void [memorymanagement] memorymanagement. frankclasswithdispose: dispose ()
23 il_0025: NOP
24 il_0026: NOP
25 il_0027: endfinally
26} // end Handler
27 il_0028: NOP
28 il_0029: newobj instance void [memorymanagement] memorymanagement. frankclasswithdispose:. ctor ()
29 il_002e: stloc.1
30. Try
31 {
32 il_002f: NOP
33 il_0030: NOP
34 il_0031: Leave. s il_0045
35} // end. Try
36 finally
37 {
38 il_0033: ldloc.1
39 il_0034: ldnull
40 il_0035: CEQ
41 il_0037: stloc. s CS $4 $0000
42 il_0039: ldloc. s CS $4 $0000
43 il_003b: brtrue. s il_0044
44 il_003d: ldloc.1
45 il_003e: callvirt instance void [mscorlib] system. idisposable: dispose ()
46 il_0043: NOP
47 il_0044: endfinally
48} // end Handler
49
The Using statement has the same effect to release unmanaged object Resources. This is also frequently encountered in the interview, which of the following are the usage of the using keyword and so on. The basic ideal answer is that apart from referencing a namespace and setting an alias for a namespace, this usage achieves the same effect as try finally blocks for the collection of unmanaged object Resources. It is just a simple way of writing.

When you use the dispose method to release an unmanaged object, you should call GC. suppressfinalize. If the object is in the Finalization queue, GC. suppressfinalize will prevent GC from calling the Finalize method. Because the call of the Finalize method sacrifices some performance. If your dispose method has cleared the delegate manager resources, you do not need to have GC call the Finalize method (msdn) of the object ). The msdn code is attached for your reference.

Code
Public class baseresource: idisposable
{
// Point to external unmanaged Resources
Private intptr handle;
// Other managed resources used in this class.
Private component components;
// Trace whether to call the. dispose method, identify space, and control the behavior of the Garbage Collector
Private bool disposed = false;

// Constructor
Public baseresource ()
{
// Insert appropriate constructor code here.
}

// Implement the interface idisposable.
// Cannot be declared as virtual.
// The subclass cannot override this method.
Public void dispose ()
{
Dispose (true );
// Exit the Finalization queue of the end queue
// Sets the object's blocking Terminator code
//
GC. suppressfinalize (this );
}

// The execution of dispose (bool disposing) is divided into two different situations.
// If disposing is equal to true, the method has been called
// Or indirectly called by user code. Both hosted and unmanaged code can be released
// If disposing is equal to false, the method has been called internally by the finalizer,
// You cannot reference other objects. Only unmanaged resources can be released.
Protected virtual void dispose (bool disposing)
{
// Check whether dispose has been called.
If (! This. disposed)
{
// If true, all managed and unmanaged resources are released.
If (disposing)
{
// Release managed resources.
Components. Dispose ();
}
// Release unmanaged resources. If disposing is false,
// Only the following code is executed.
Closehandle (handle );
Handle = intptr. zero;
// Note that this is not thread-safe.
// After the managed resources are released, other threads can be started to destroy objects,
// But before the disposed flag is set to true
// If thread security is required, the client must implement it.

}
Disposed = true;
}
// Call the method using InterOP
// Clear unmanaged resources.
[System. runtime. interopservices. dllimport ("Kernel32")]
Private extern static Boolean closehandle (intptr handle );

// Use the C # destructor to implement the terminator code
// This can be called and executed only when the dispose method is not called.
// If you give the opportunity to terminate the base class.
// Do not provide destructor to sub-classes.
~ Baseresource ()
{
// Do not duplicate the cleanup code.
// Based on reliability and maintainability, calling dispose (false) is the best method.
Dispose (false );
}

// You can call the dispose method multiple times,
// But an exception is thrown if the object has been released.
// No matter when you process the object, the system checks whether the object is released,
// Check to see if it has been disposed.
Public void dosomething ()
{
If (this. disposed)
{
Throw new objectdisposedexception ();
}
}
For more natural types that require calling the close method than the dispose method, you can add a close method in the base class.
The close method does not call the dispose method to execute proper cleanup.
The following example demonstrates the close method.
// Do not set the method to virtual.
// The inherited class cannot override this method.
Public void close ()
{
// Call the dispose parameter without any parameters.
Dispose ();
}

Public static void main ()
{
// Insert code here to create
// And use a baseresource object.
}
}

 

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.