Negative C # Chapter 2:. NET Resource Management)

Source: Internet
Author: User

Chapter 2.. NET Resource Management
Chapter 2:. NET Resource Management

A simple fact:. Net ApplicationsProgramIt runs in a hosted environment. This environment has a lot of conflicts with different designers, so there is always Objective C #. To greatly discuss the benefits of this environment, you need to change your thoughts on the local environment to. Net CLR. This means you need to understand the. NET garbage collector. When you understand the content recommended in this chapter, it is necessary to have a rough understanding of the. NET memory management environment. Let's get to know about it.

The garbage collector (GC) controls your managed memory. Unlike the local running environment, you don't have to worry about memory leakage, variable pointers, Uninitialized pointers, or other memory management service problems. But the garbage collector is not a myth: You need to clean it yourself. You are responsible for unmanaged resources, such as file handles, data links, GDI + objects, COM objects, and other system objects.

The good news is that a clear design style can be easily implemented due to GC memory management. Circular reference is very easy, whether it is a simple link or a complex webpage object. GC labeling and rigorous and efficientAlgorithmThese links can be detected and inaccessible webpage objects can be completely deleted. GC determines whether an object is reachable through the "Roaming" of the tree structure starting from the root object of the application, rather than forcing each object to maintain reference tracking, com. Dataset is a good example of how such an algorithm simplifies and determines the relationship between objects. Dataset is a datatable set. Each datatable is a set of datarow, and each datarow is a set of dataitems. datacolum defines these types of relationships. Here there are some references from dataitem to its columns. At the same time, datatime also has a container referenced to it, that is, datarow. Datarow includes references to datatable, and each object finally contains a reference to dataset.
The author wants to say: You see, GC can easily deal with such a complex reference relationship. Do you think GC is very powerful ?)

If this is not complex enough, you can create a dataview that provides sequential access to filtered data tables. These are all managed by dataviewmanager. All these references that run through the web page constitute dataset. Releasing memory is the responsibility of GC. Because the. NET Framework designer frees you from releasing these objects, these complex web object references will not cause problems. There is no need to care about the proper release sequence of these web page objects, which is the work of GC. The GC design structure can simplify these problems and identify these webpage objects as garbage. After the application ends its reference to dataset, no one can reference its sub-objects ). Therefore, there are no objects in the web page that reference dataset cyclically. datatables are no longer important because these objects are no longer accessible in applications and they are junk.

The garbage collector runs on its own thread to Remove unused memory from your program. It also compresses the managed heap every time it runs. The compressed heap is to move the active objects in the managed heap together, so that the continuous memory can be empty. Figure 2.1 shows two memory snapshots without garbage collection. All idle memory continues after garbage collection.


Figure 2.1 The Garbage Collector not only moves memory that is not used, but also removes other objects to compress the memory used, giving up the most idle memory.

As you first learned, the full responsibility of the garbage collector is memory management. However, you are responsible for all system resources. You can define a destructor for your type to release some system resources. The Destructor is called by the system before the Garbage Collector removes objects from the memory. You can, and you must, release any unmanaged resources you occupy. Object destructor are sometimes called after the object becomes garbage, but before the memory is returned. This undefined destructor means that the relationship between the object's destructor and its stopping use cannot be controlled. For GC, I recommend that you refer to the garbage collector discussed in Jeffrey's ". NET Framework programming (revision ). This is a major change for C ++, and there is a major difference in design. Classes written by experienced C ++ programmers apply for memory in the constructor and release them in the Destructor:
// Good C ++, bad C #:
Class criticalsection
{
Public:
// Constructor acquires the system resource.
Criticalsection ()
{
Entercriticalsection ();
}

// Destructor releases system resource.
~ Criticalsection ()
{
Exitcriticalsection ();
}
};

// Usage:
Void func ()
{
// The lifetime of S controls access
// The system resource.
Criticalsection S;
// Do work.

//...

// Compiler generates call to destructor.
// Code exits critical section.
}

This is a common C ++ style that ensures that resources are released without exceptions. But this does not work in C #. At least, it is different from this. A definite destructor is not a part of the. NET environment or C. Forcing the C ++ style to use destructor in C # Won't make it work normally. In C #, The Destructor runs correctly, but it does not run instantly. In the previous example,CodeIt is ultimately in the critical section, but in C #, when the Destructor exists, it is not in the critical section. It runs at an unknown time. You don't know when or when.

Lazy destructor also results in performance loss. The object to be destructed is placed with a performance poison agent on the garbage collector. When GC finds that an object is SPAM but requires analysis, it cannot directly Delete the object from the memory. First, it needs to call the destructor, but the Destructor does not run on the same thread of the garbage collector. Instead, GC has to place the object in the Destructor queue and let another thread execute all the destructor. GC continues its work and removes other garbage from memory. During the next GC collection, the destructed objects will be removed from the memory. Figure 2.2 shows different GC conditions for the three memories. Note that the objects to be destructed will remain in the memory until the next GC recycle.


Figure 2.2 this sequence shows the role of the Destructor on the garbage collector. The object will exist in the memory for a longer period of time. You need to start another thread to run the garbage collector.

This makes you believe that the objects to be destructed must survive at least one GC recycle loop in the memory. But I simplified these things. In fact, because there is only one GC involved in another GC, the author wants to reference the issue of recycling .), This makes the situation much more complicated .. Net recycler uses "Generation" to optimize this problem. Generation can help GC to quickly identify objects that seem to be spam. Therefore, the object created since the last time is called The 0th generation object, and all the objects that still exist after a GC collection are called the 1st generation object. All the objects that still exist after two or more GC collections are called 2nd-generation objects, therefore, there can be a maximum of 2nd generation objects. If GC supports more generations in the future, a more generation object will appear ,. both. NET 1.1 and. 2.0 support only three generations, which is a reasonable number confirmed by MS ).

The purpose of generational division is to differentiate temporary variables and global variables of some applications. The 0th generation object may be a temporary variable. Member variables and some global variables will soon become 1st-generation objects and eventually become 2nd-generation objects.

GC checks 1st and 2nd generation objects to optimize its work. Each GC cycle detects 0th generation objects. A rough assumption is that a GC will detect more than 10 times to detect 0th generation objects, and more than 100 times to detect all objects. Consider the overhead of the Destructor again: an object that requires the Destructor may need more than nine GC recycling cycles than an object that does not need the destructor in the memory. If it is not destructed, it will move to the 2nd generation object. In a 2nd-generation object, one can survive the first 100 GC cycles until the next 2nd-generation collection (not understanding, not knowing what to say ).

At the end, remember the biggest benefit of a garbage collector hosting environment responsible for memory management: Memory leakage. Other pointer service problems are not yours. Non-memory resources force you to use destructor to ensure that non-memory resources are cleared. Destructor may affect the performance of your applications, but you must use them to prevent resource leakage, it generally refers to file handles, network resources, or other resources that cannot be stored in the memory ). Implement the idisposable interface to avoid performance loss caused by destructor on the garbage collector. The following principles will help you develop programs in a more effective environment.

 

Chapter 2.. NET Resource Management
The simple fact that. net programs run in a managed environment has a big impact on the kinds of designs that create valid tive C #. taking utmost advantage of that environment requires changing your thinking from native environments to. net CLR. it means understanding. net garbage collector. an overview of. net memory management environment is necessary to understand the specific recommendations in this chapter, so let's get on with the overview.

The garbage collector (GC) controls managed memory for you. unlike native environments, you are not responsible for memory leaks, dangling pointers, Uninitialized pointers, or a host of other memory-management issues. but the garbage collector is not magic: You need to clean up after yourself, too. you are responsible for unmanaged resources such as file handles, database connections, GDI + objects, COM objects, and other system objects.

Here's the good news: Because the GC controls memory, certain design idioms are much easier to implement. circular references, both simple relationships and complex webs of objects, are much easier. the GC's Mark and compact algorithm efficiently detects these relationships and removes unreachable webs of objects in their entirety. the GC determines whether an object is reachable by walking the object tree from the application's root object instead of forcing each object to keep track of references to it, as in COM. the dataset class provides an example of how this algorithm simplifies object ownership decisions. a dataset is a collection of datatables. each datatable is a collection of datarows. each datarow is a collection of dataitems. each datatable also contains a collection of datacolumns. datacolumns define the types associated with each column of data. there are other references from the dataitems to its appropriate column. every dataitem also contains a reference to its container, the datarow. datarows contain references back to the datatable, And everything contains a reference back to the containing dataset.

if that's not complicated enough, you can create dataviews that provide access to filtered sequences of a data table. those are all managed by a dataviewmanager. there are references all through the web of objects that make up a dataset. releasing memory is the GC's responsibility. because. net Framework designers did not need to free these objects, the complicated web of object references did not pose a problem. no demo-needed to be made regarding the proper sequence of freeing this web of objects; it's the GC's job. the GC's design simplifies the problem of identifying this kind of web of objects as garbage. after the application releases its reference to the dataset, none of the subordinate objects can be reached. it does not matter that there are still circular references to the dataset, datatables, and other objects in the web. because these objects cannot be reached from the application, they are all garbage.

The garbage collector runs in its own thread to Remove unused memory from your program. it also compacts the managed heap each time it runs. compacting the heap moves each live object in the managed heap so that the free space is located in one contiguous block of memory. figure 2.1 shows two snapshots of the heap before and after a garbage collection. all free memory is placed in one contiguous block after each GC operation.


Figure 2.1. the Garbage Collector not only removes unused memory, but it moves other objects in memory to compact used memory and maximize free space.

as you 've just learned, memory management is completely the responsibility of the garbage collector. all other system resources are your responsibility. you can guarantee that you free other system resources by defining a finalizer in your type. finalizers are called by the system before an object that is garbage is removed from memory. you canand mustuse these methods to release any unmanaged resources that an object owns. the finalizer for an object is called at some time after it becomes garbage and before the system reclaims its memory. this Nondeterministic finalization means that you cannot control the relationship between when you stop using an object and when its finalizer executes. that is a big change from C ++, and it has important ramifications for your designs. experienced C ++ programmers wrote classes that allocated a critical resource in its constructor and released it in its destructor:

// Good C ++, bad C #:
Class criticalsection
{
Public:
// Constructor acquires the system resource.
Criticalsection ()
{
Entercriticalsection ();
}

// Destructor releases system resource.
~ Criticalsection ()
{
Exitcriticalsection ();
}
};

// Usage:
Void func ()
{
// The lifetime of S controls access
// The system resource.
Criticalsection S;
// Do work.

//...

// Compiler generates call to destructor.
// Code exits critical section.
}

 

this common C ++ idiom ensures that resource deallocation is exception-proof. this doesn't work in C #, howeverat least, not in the same way. deterministic finalization is not part of. NET environment or the C # language. trying to force the C ++ idiom of deterministic finalization into the C # Language won't work well. in C #, The finalizer eventually executes, but it doesn't execute in a timely fashion. in the previous example, the code eventually exits the critical section, but, in C #, It doesn't exit the critical section when the function exits. that happens at some unknown time later. you don't know when. you can't know when.

relying on finalizers also introducesperformance penalties. objects that require finalization put a performance drag on the garbage collector. when the GC finds that an object is garbage but also requires finalization, it cannot remove that item from memory just yet. first, it callthe finalizer. finalizers are not executed by the same thread that collects garbage. instead, the GC places each object that is ready for finalization in a queue and spawns yet another thread to execute all the finalizers. it continues with its business, removing other garbage from memory. on the next GC cycle, those objects that have been finalized are removed from memory. figure 2.2 shows three different GC operations and the difference in memory usage. notice that the objects that require finalizers stay in memory for extra cycles.


figure 2.2. this sequence shows the effect of finalizers on the garbage collector. objects stay in memory longer, and an extra thread needs to be spawned to run the garbage collector.

This might lead you to believe that an object that requires finalization lives in memory for one GC cycle more than necessary. but I simplified things. it's more complicated than that because of another GC design demo. the. net Garbage Collector defines generations to optimize its work. generations help the GC identify the likeliest garbage candidates more quickly. any object created since the last garbage collection operation is a generation 0 object. any object that has ved one GC operation is a generation 1 object. any object that has ved two or more GC operations is a generation 2 object. the purpose of generations is to separate local variables and objects that stay around for the life of the application. generation 0 objects are mostly local variables. member variables and global variables quickly enter Generation 1 and eventually enter generation 2.

the GC optimizes its work by limiting how often it examines first-and second-generation objects. every GC cycle examines generation 0 objects. roughly 1 GC out of 10 examines the generation 0 and 1 objects. roughly 1 GC cycle out of 100 examines all objects. think about finalization and its cost again: an object that requires finalization might stay in memory for nine GC cycles more than it wowould if it did not require finalization. if it still has not been finalized, it moves to generation 2. in generation 2, an object lives for an extra 100 GC cycles until the next generation 2 Collection.

to close, remember that a managed environment, where the Garbage Collector takes the responsibility for memory management, is a big plus: memory leaks and a host of other pointer-related problems are no longer your problem. nonmemory resources force you to create finalizers to ensure proper cleanup of those nonmemory resources. finalizers can have a serious impact on the performance of your program, but you must write them to avoid resource leaks. implementing and using the idisposable interface avoids the performance drain on the garbage collector that finalizers introduce. the next section moves on to the specific items that will help you create programs that use this environment more than tively.

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.