当前位置: 永利棋牌 > 儿童文学 > 正文

0对垃圾回收机制的改进2,0垃圾回收机制的改进

时间:2019-10-01 13:19来源:儿童文学
A survey of garbage collection and the changes CLR 4.0 brings in -series of what is new in CLR 4.0 导言Introduction   垃圾回收(Garbage Collection)在.net中是一个很重要的机制.本文将要谈到CLR4.0对垃圾回收做了哪些

A survey of garbage collection and the changes CLR 4.0 brings in - series of what is new in CLR 4.0
导言Introduction
  垃圾回收(Garbage Collection)在.net中是一个很重要的机制. 本文将要谈到CLR4.0对垃圾回收做了哪些改进. 为了更好地理解这些改进, 本文也要介绍垃圾回收的历史.  这样我们对整个垃圾回收有一个大的印象. 这个大印象对于我们掌握.net架构是有帮助的.

A survey of garbage collection and the changes CLR 4.0 brings in Part 2

A survey of garbage collection and the changes CLR 4.0 brings in Part 3

  Garbage Collection is an important component of .net. The post will talk about what has been improved in CLR 4.0. To understand it, I will take a survey of the history of garbage collection. This way we can have a big picture of garbage collection. This will help us master .net architecture in comprehensive manner.

  • series of what is new in CLR 4.0
    接前篇Continue the previous post .net CLR 4.0对垃圾回收机制的改进
  • series of what is new in CLR 4.0
    接前篇Continue the previous posts

关于垃圾回收About Garbage collection
  在C++时代,我们需要自己来管理申请内存和释放内存. 于是有了new, delete关键字. 还有的一些内存申请和释放函数(malloc/free). C++程序必须很好地管理自己的内存, 不然就会造成内存泄漏(Memory leak). 在.net时代, 微软为开发人员提供了一个强有力的机制--垃圾回收. 垃圾回收机制是CLR的一部分, 我们不用操心内存何时释放, 我们可以花更多精力关注应用程序的业务逻辑. CLR里面的垃圾回收机制用一定的算法判断某些内存程序不再使用,回收这些内存并交给我们的程序再使用.

CLR4.0所带来的变化仍然没有在这篇,请看下篇。

 .net CLR 4.0对垃圾回收机制的改进

  In the times of C++, we need to allocate and release memory by ourselves carefully,  therefore there are new, delete keywords in C++, and fuctions(malloc/free) to allocate and release memory. C++ program has to manage its memory well, otherwise there will be memory leak. In .net, Microsoft provides a strong machanism to developers—Garbage collection. The Garbage collection is part of CLR. We do not need to worry about when to release memory. We can spend more time on buisness logic of applications. The Garbage colleciton of CLR adopts algorithms to decide which part of memory the program does not need any more, and then release these memory for further use.

内存释放和压缩
创建对象引用图之后,垃圾回收器将那些没有在这个图中的对象(即不再需要的对象)释放。释放内存之后, 出现了内存碎片, 垃圾回收器扫描托管堆,找到连续的内存块,然后移动未回收的对象到更低的地址, 以得到整块的内存,同时所有的对象引用都将被调整为指向对象新的存储位置。这就象一个夯实的动作。

.net CLR 4.0对垃圾回收机制的改进2

垃圾回收的功能The functionalities of Garbage collection
  用来管理托管资源和非托管资源所占用的内存分配和释放。In charging of the releasing and re-allocation of memory of managed and unmanaged resources.

After building up the reference relationship graph, garbage collector reclaims the objects not in the graph(no longer needed), after releasing the objects not in the graph, there is memory scrap. Garbage collector scans the managed heap to find continous memory block, and shifts the remaining objects to lower address to get consecutive memory space, and then adjusts the references of objects according to the shifted address of objects. This is looking like a tamping on the managed heap.

 

  寻找不再使用的对象,释放其占用的内存, 以及释放非托管资源所占用的内存. Find the objects no longer needed, release the memory the objects occupied, and affranchise memory occupied by unmanaged resources.

下面要说到的是代的概念。代概念的引入是为了提高垃圾收集器的整体性能。We come to the concept of generations next. The importing of generation concept is to improve the performance of garbage collector.

弱引用Weak Reference

  垃圾回收器释放内存之后, 出现了内存碎片, 垃圾回收器移动一些对象, 以得到整块的内存,同时所有的对象引用都将被调整为指向对象新的存储位置。After releasing the memory no longer needed, there is memory scrap. Garbage collector shifts objects to get consecutive memory space, and then the references of objects will be adjusted according to the shifted address of objects.

代Generations
请想一想如果垃圾收集器每次总是扫描所有托管堆中的对象,对性能会有什么影响。会不会很慢?是的。微软因此引入了代的概念。

mm小游戏

下面我们来看看CLR是如何管理托管资源的. Let’s see how CLR takes care of managed resources.

Please think about what will happen if garbage collector scans all the objects in the whole heap in every garbage collecting cycle. Will it be very slow? Yes, therefore Microsoft imported the concept of generations.

弱引用是相对强引用来说的。强引用指的是根有一个指针指向对象。弱引用是通过对强引用加以弱化而得到的。这个弱化的手段就是用System.WeakReference类。所以精确地说,强引用指的是根有一个非WeakReference类型的指针指向对象,而弱引用就是根有一个WeakReference类型的指针指向对象。垃圾收集器看到一个WeakReference类型的根指向某个对象,就会特别处理。所以在垃圾收集器创建对象引用关系图的时候,如果遇到一个弱引用指针,那么垃圾收集器就不会将其加入图中。如果一个对象只有弱引用指向它,那么垃圾收集器可以收集此对象。一旦将一个强引用加到对象上,不管对象有没有弱引用,对象都不可回收。

托管堆和托管栈Managed heap and Managed stack:
.net CLR在运行我们的程序时,在内存中开辟了两块地方作不同的用处--托管栈和托管堆. 托管栈用来存放局部变量, 跟踪程序调用与返回. 托管堆用来存放引用类型. 引用类型总是存放于托管堆. 值类型通常是放在托管栈上面的. 如果一个值类型是一个引用类型的一部分,则此值类型随该引用类型存放于托管堆中. 哪些东西是值类型? 就是定义于System.ValueType之下的这些类型:

为什么代的概念可以提高垃圾收集器的性能?因为微软是基于对大量编程实践的科学估计,做了一些假定而这些假定符合绝大多数的编程实践:

 

bool byte char decimal double enum float int long sbyte short struct uint ulong ushort

Why generation concept can help improve performance of garbage collector? Because Microsoft did scientific valuation on mass of programming practice, and made assumptions and the assumptions conform to most of programming practice:

Weak reference is corresponding to strong reference. Strong reference is that a root is pointing to an object. Weaken a strong reference and get a weak reference. The facility to weaken strong reference is the System.WeakReference class.  An exact definition is that, strong reference is that a root has a non-System.WeakReference type pointer pointing to an object, and weak reference is that a root has a System.WeakReference type pointer pointing to an object. Garbage collector treats the roots of WeakReference type in a special way. Therefore, when garbage collector is building the reference relationship graph, if there is a weak reference pointer, and then garbage collector will not append it to the graph. If an object only has weak references pointing to it, garbage collector can collect the object. Once a strong reference is pointing to the object, no matter whether the object has weak references or not, the object can not be collected.

When .net CLR runs our program, CLR declares two ranges of memory for different purposes. Managed stack is to store local variables, and trace the call and return of routines. Managed heap is to store reference types. Usually value types was put on managed stack. If a value type is a part of a reference type, then the value type will be stored in managed heap along with the reference type. What are value types? They are the types defined in System.ValueType:

越新的对象,其生命周期越短。The newer an object is, the shorter its lifetime will be.
越老的对象,其生命周越长。The older an object is, the longer its lifetime will be.
新对象之间通常有强的关系并被同时访问。Newer objects tend to have strong relationships to each other and are frequently accessed around the same time.
压缩一部分堆比压缩整个堆快。Compacting a portion of the heap is faster than compacting the whole heap.
有了代的概念,垃圾回收活动就可以大部分局限于一个较小的区域来进行。这样就对垃圾回收的性能有所提高。After importing the concept of generations, most of garbage collecting will be limited in in smaller range of memory. This enhances the performance of garbage collector.

垃圾收集器对WeakReference类的特别处理从new操作就开始。通常的类,只要new操作,就会从托管堆分配空间,而WeakReference类的new操作不是这样做的。我们先来看WeakReference类的构造函数:

bool byte char decimal double enum float int long sbyte short struct uint ulong ushort

让我们来看垃圾收集器具体是怎么实现代的: Let’s see how generations are exactly implemented in garbage collector:

The special treatment that garbage collector deals with WeakReference class starts from the new operation. A common class will allocate space from managed heap when new operation, but CLR does not do like that for WeakReference class when new operation. Let’s look at the constructors of WeakReference class:

什么是引用类型呢? 只要用class, interface, delegate, object, string声明的类型, 就是引用类型.  What are reference types? The types declared with class, interface, delegate, object, stirng, are reference types.

第0代:新建对象和从未经过垃圾回收对象的集合   Generation 0: A collection of newly created object and the objects never collected.

WeakReference(Object target);

我们定义一个局部变量, 其类型是引用类型. 当我们给它赋一个值, 如下例:We declare a local variable, which is a reference type, and we assign a value to the local variable, like the following:

第1代:在第0代收集活动中未回收的对象集合  Generation 1: A collection of objects not collected by garbage collector in collecting cycle of generation 0.

美女小游戏

private void MyMethod()
{
   MyType  myType = new MyType();
   myType.DoSomeThing();
}
在此例中, myType 是局部变量, new实例化出来的对象存储于托管堆, 而myType变量存储于托管栈. 在托管栈的myType变量存储了一个指向托管堆上new实例化出来对象的引用. CLR运行此方法时, 将托管栈指针移动, 为局部变量myType分配空间, 当执行new时, CLR先查看托管堆是否有足够空间, 足够的话就只是简单地移动下托管堆的指针, 来为MyType对象分配空间, 如果托管堆没有足够空间, 会引起垃圾收集器工作. CLR在分配空间之前,知道所有类型的元数据,所以能知道每个类型的大小, 即占用空间的大小.

第2代:在第1和第2代中未回收的对象集合, 即垃圾收集器最高只支持到第2代, 如果某个对象在第2代的回收活动中留下来,它仍呆在第2代的内存中。 Generation 2: A collection of objects not collected by garbage collector in generation 1 and generation 2. This means the highest generation that garbage collector supports is generation 2. If an object survives in generation 2 collecting cycle, it still remains in memory of generation 2.

WeakReference(Object target, Boolean trackResurrection);

In this sample, myType is a local variable. the object instantiated by new operation is stored in managed heap, and the myType local variable is stored in managed stack. The myType local variable on managed stack has a pointer pointing to the address of the object instantiated by new operation. When CLR executes the method, CLR moves the pointer of managed stack to allocate memory for the local variable myType. When CLR executes new operation, CLR checks first whether managed heap has enough space, if enough then do a simple action – move the pointer of managed heap to allocate space for the object of MyType. If managed heap does not have space, this triggers garbage collector to function. CLR knows all the metadata of types, and knows the size of all the types, and then knows how big space the types need.

当程序刚开始运行,垃圾收集器分配为每一代分配了一定的内存,这些内存的初始大小由.net framework的策略决定。垃圾收集器记录了这三代的内存起始地址和大小。这三代的内存是连接在一起的。第2代的内存在第1代内存之下,第1代内存在第0代内存之下。应用程序分配新的托管对象总是从第0代中分配。如果第0代中内存足够,CLR就很简单快速地移动一下指针,完成内存的分配。这是很快速的。当第0代内存不足以容纳新的对象时,就触发垃圾收集器工作,来回收第0代中不再需要的对象,当回收完毕,垃圾收集器就夯实第0代中没有回收的对象至低的地址,同时移动指针至空闲空间的开始地址(同时按照移动后的地址去更新那些相关引用),此时第0代就空了,因为那些在第0代中没有回收的对象都移到了第1代。

此二构造函数都需要一个对象的引用,第二个构造函数还需要一个布尔值参数来表示我们是否需要跟踪对象的重生。此参数的意义后文会交代。

当CLR完成MyMethod方法的执行时, 托管栈上的myType局部变量被立即删除, 但是托管堆上的MyType对象却不一定马上删除. 这取决于垃圾收集器的触发条件.后面要介绍此触发条件.When CLR finishs execution of MyMethod method, the local variable myType on managed stack is deleted immediately, but the object of MyType on managed heap may not be deleted immediately. This depends on the trigger condition of garbage collector. I will talk about the trigger condition later.

When the program initializes, garbage collector allocates memory for generations. The initial size of memory blocks are determined according to the strategies of the .net framework. Garbage collector records the start address and size of the memory block for generations. The memory blocks of generations are continuous and adjacent. The memory of generation 2 is under the memory of generation 1, and the memory of generation 1 is under the memory of generation 0. CLR always allocates memory for new objects in generation 0. If there is enough memory in generation 0, CLR simply moves the pointer to allocate memory. This is really fast. When there is not enough memory in generation 0 to accommodate new objects, CLR triggers garbage collector starts to collect objects no longer needed from generation 0. When the collecting action in generation 0 finishs, garbage collector tamps(or compacts) the objects not collected in generation 0 to lower address, and moves the pointer to start address of free memory(and updates the related references according to the shifted address of objects). At this time, generation 0 is empty, because the objects survived in generation 0 are moved to generation 1.

The two constructors both need a reference of an object, and the second constructor needs one more, a parameter of boolean type to indicate whether we need to track the resurrection of the object. The exact meaning of the parameter will be talked about later.

上面我们了解了CLR如何管理托管资源. 下面我们来看垃圾收集器如何寻找不再使用的托管对象,并释放其占用的内存. In previous paragraphs, we learn how CLR manages managed resources. In following paragraphs, we will see how garbage collector find objects no longer needed, and release the memory.

当只对第0代进行收集时,所发生的就是部分收集。这与之前所说的全部收集有所区别(因为代的引入)。对第0代收集时,同样是从根开始找那些正引用的对象,但接下来的步骤有所不同。当垃圾收集器找到一个指向第1代或者第2代地址的根,垃圾收集器就忽略此根,继续找其他根,如果找到一个指向第0代对象的根,就将此对象加入图。这样就可以只处理第0代内存中的垃圾。这样做有个先决条件,就是应用程序此前没有去写第1代和第2代的内存,没有让第1代或者第2代中某个对象指向第0代的内存。但是实际中应用程序是有可能写第1代或者第2代的内存的。针对这种情况,CLR有专门的数据结构(Card table)来标志应用程序是否曾经写第1代或者第2代的内存。如果在此次对第0代进行收集之前,应用程序写过第1代或者第2代的内存,那些被Card Table登记的对象(在第1代或者第2代)将也要在此次对第0代收集时作为根。这样,才可以正确地对第0代进行收集。

假设我们有两个类MyClass和MyAnotherClass,都有Finalize方法。我们声明两个对象:

垃圾收集器如何寻找不再使用的托管对象,并释放其占用的内存How garbage collector find objects no longer needed and release memory
前面我们了解了CLR如何管理托管栈上的对象.按照先进后出原则即可比较容易地管理托管栈的内存. 托管堆的管理比托管栈的管理复杂多了.下面所谈都是针对托管堆的管理. In previous paragraphs, we learn how CLR manages the objects on managed stack. It is easy to manage managed stack as long as you utilize the rule “first in last out”. The management of managed heap is much more complicated than the management of managed stack. The following is all about the management of managed heap.

When collecting generation 0 only, it is partial collection. It is different from full collection mentioned earlier(because of the generations). When collecting generation 0, garbage collector starts from the roots, which is the same as the full collection, but it is different in coming steps. When garbage collector finds a root pointing to an address of generation 1 or 2, garbage collector ignores the root, and goes to next root. If garbage collector finds a root pointing to an object of generation 0, garbage collector addes the object into the graph. That way garbage collector processes the objects of generation 0 only. There is a pre-condition to do that. It is that the application does not write to the memory of generation 1 and 2, does not allow some objects of generation 1 or 2 refer to the memory of generation 0. But in our daily work, the applicaiton is possible to write the memory of generation 1 or 2. In this case, CLR has a dedicated data structure called Card Table to record whether the application writes the memory of generation 1 or 2. If the application writes the memory of generation 1 or 2 before the collecting on generation 0, the objects recorded by the Card Table will become roots during the collecting on generation 0. Garbage collection on generation 0 can be done correctly in this case.

Suppose we have two classesMyClass and MyAnotherClass, and both of classes have Finalize method.

根The root
垃圾收集器寻找不再使用的托管对象时, 其判断依据是当一个对象不再有引用指向它, 就说明此对象是可以释放了. 一些复杂的情况下可以出现一个对象指向第二个对象,第二个对象指向第三个对象,…就象一个链表. 那么, 垃圾收集器从哪里开始查找不再使用的托管对象呢? 以刚才所说的链表为例, 显然是应该从链表的开头开始查找. 那么,在链表开头的是些什么东东呢? The criteria garbage collector uses to judge whether an object is no longer needed is that an object can be released when the object does have any reference. In some complicated cases, it happends that the first object refers to the second object, and the second object points to the third object, etc. It is looking like a chain of single linked nodes. Then the question is : where does the garbage collector begins to find objects no longer needed? For the example of the single linked node chain, we can say it is obvious garbage collector starts from the beginning of the chain. Then the next question is: what are the stuff at the beginning of the chain.

以上说到了第0代收集发生的一个条件,即第0代没有足够内存去容纳新对象。执行GC.Collect()也会触发对第0代的收集。另外,垃圾收集器还为每一代都维护着一个监视阀值。第0代内存达到这个第0代的阀值时也会触发对第0代的收集。对第1代的收集发生在执行GC.Collect(1)或者第1代内存达到第1代的阀值时。第2代也有类似的触发条件。当第1代收集时,第0代也需要收集。当第2代收集时,第1和第0代也需要收集。在第n代收集之后仍然存留下来的对象将被转移到第n+1代的内存中,如果n=2, 那么存留下来的对象还将留在第2代中。

MyClass myObject = new MyClass();

是局部变量, 全局变量, 静态变量, 指向托管堆的CPU寄存器. 在CLR中,它们被称之为根. The answer is : local variables, global variables, static variables, the CPU registers pointing to managed heap. In CLR, they are called “the roots”.

We mentioned a criteria to trigger collecting on generation 0 in above paragraphs: generation 0 does not have enough memory to accommodate new objects. When execute GC.Collect(), it launches collecting on generation 0 also. In addition, garbage collector sets up a threshold for each of generations. When the memory of generation 0 reaches the threshold, collecting on generation 0 happens also. Collecting on generation 1 happens when executing GC.Collect() or the memory of generation 1 reaches the threshold of generation 1. Generation 2 has similar trigger conditions. When collecting on generation 1, collecting on generation 0 happens also. When collecting on generation 2, collecting on generation 1 and 0 happen also. The survived object in collecting generation n will be moved to the memory of generation n+1. If n=2, the remaining objects still stay in generation 2.

MyAnotherClass myAnotherObject = new MyAnotherClass();

有了开始点, 垃圾收集器接下来怎么做呢? Got the roots, what will garbage collector do next?

对象结束Finalization of objects
对象结束机制是程序员忘记用Close或者Dispose等方法清理申请的资源时的一个保证措施。如下的一个类,当一个此类的实例创建时,在第0代中分配内存,同时此对象的引用要被加入到一个由CLR维护的结束队列中去。

当我们用这样的代码声明一个弱引用对象: WeakReference myShortWeakReferenceObject = new WeakReference( myObject );

创建一个图, 一个描述对象间引用关系的图. Build a graph, which shows the reference relationship among objects.
垃圾收集器首先假定所有在托管堆里面的对象都是不可到达的(或者说没有被引用的,不再需要的), 然后从根上的那些变量开始, 针对每一个根上的变量, 找出其引用的托管堆上的对象, 将找到的对象加入这个图, 然后再沿着这个对象往下找,看看它有没有引用另外一个对象, 有的话,继续将找到的对象加入图中,如果没有的话, 就说明这条链已经找到尾部了. 垃圾收集器就去从根上的另外一个变量开始找, 直到根上的所有变量都找过了, 然后垃圾收集器才停止查找. 值得一提的是, 在查找过程中, 垃圾收集器有些小的优化, 如: 由于对象间的引用关系可能是比较复杂的, 所以有可能找到一个对象, 而此对象已经加入图了, 那么垃圾收集器就不再在此条链上继续查找, 转去其他的链上继续找. 这样对垃圾收集器的性能有所改善.

Finalization is an ensuring mechanism when programmers forget to use Close or Dispose method to clean up resources. For exmaple, a class like the following, when an instane of the class is created, it is allocated in memory of generation 0, and a reference of the object is appended to Finalization queue maintained by CLR.

When we use such a snippet of code to declare a weak reference object: WeakReference myShortWeakReferenceObject = new WeakReference( myObject );

First garbage collector supposes all the objects in managed heap are not reachable( do not have reference, or no longer needed). Then start from the variables in the roots. For each of the variable in the roots, search the object the variable refers to, and add the found object into the graph, and search again after the found object for next refered object, etc. Check whether the found object has next reference. If has, continue to add the next found object into the graph. If not, it means this is the end of the chain, then stop searching on the chain, continue on next variable in the roots, keep searching on roots, until all the searching are finished. In the searching process, garbage collector has some optimization to improve the performance. Like: Because the reference relationship could be complicated among objects, it is possible to find an object that has been added into the graph, then garbage collector stops searching on the chain, continue to search next chain. This way helps on performance of garbage collection.

public class BaseObj {    public BaseObj() { }     protected override void Finalize() {        // Perform resource cleanup code here...        // Example: Close file/Close network connection        Console.WriteLine("In Finalize.");    }}当此对象成为垃圾时,垃圾收集器将其引用从结束队列移到待结束队列中,同时此对象会被加入引用关系图。一个独立运行的CLR线程将一个个从待结束队列(Jeffrey Richter称之为Freachable queue)取出对象,执行其Finalize方法以清理资源。因此,此对象不会马上被垃圾收集器回收。只有当此对象的Finalize方法被执行完毕后,其引用才会从待结束队列中移除。等下一轮回收时,垃圾回收器才会将其回收。

垃圾收集器内部有一个短弱引用表,用这样声明的弱引用对象将不会在托管堆中分配空间,而是在短弱引用表中分配一个槽。此槽中记录对myObject的引用。New操作将此槽的地址返回给myShortWeakReferenceObject变量。

垃圾收集器建好这个图之后, 剩下那些没有在这个图中的对象就是不再需要的. 垃圾收集器就可以回收它们占用的空间.After buidling the reference graph among objects, the objects not in the graph are no longer needed objects. Garbage collector could release the memory space occupied by the no longer needed objects.

When the object becomes garbage, garbage collector moves the reference from Finalization queue to ToBeFinalized queue(Jeffrey Richter called it Freachable queue), and appends the object to the reference graph. A standalone thread of CLR will fetch objects from the ToBeFinalized queue one by one, and execute the Finalize() method of objects to clean up resources. Therefore, the object will not be collected right away by garbage collector. After the Finalize() method is executed, its reference will be removed from the ToBeFinalizaed queue. When next collecting comes, garbage collector reclaims its memory.

Garbage collector has a short weak reference table inside, the weak reference object declared in such a way will not allocate space from managed heap, and a slot will be allocated in the short weak reference table for the weak reference object. The slot records the referene of myObject. New operation returns the address of the slot to myShortWeakReferenceObject variable.

未完待续To be continued…

GC类有两个公共静态方法GC.ReRegisterForFinalize和GC.SuppressFinalize大家也许想了解一下,ReRegisterForFinalize是将指向对象的引用添加到结束队列中(即表明此对象需要结束),SuppressFinalize是将结束队列中该对象的引用移除,CLR将不再会执行其Finalize方法。

如果我们用这样的代码声明一个弱引用对象(我们要跟踪该对象的重生): WeakReference myLongWeakReferenceObject = new WeakReference( myAnotherObject, true );

参考文献References
Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework By Jeffrey Richter 

There are two public static methods of GC class you guys may want to know: GC.ReRegisterForFinalize and GC.SuppressFinalize. ReRegisterForFinalize is to append the reference of objects to finalization queue(meaning the objects need to be finalized), SuppressFinalize is to remove the reference of objects from finalization queue, then CLR would not execute the Finalize method of the object.

When we use such a snippet of code to declare a weak reference object(We need to track resurrection of the object): WeakReference myLongWeakReferenceObject = new WeakReference( myAnotherObject, true );

Garbage Collection Part 2: Automatic Memory Management in the Microsoft .NET Framework By Jeffrey Richter

因为有Finalize方法的对象在new时就自动会加入结束队列中,所以ReRegisterForFinalize可以用的场合比较少。ReRegisterForFinalize比较典型的是配合重生(Resurrection)的场合来用。重生指的是在Finalize方法中让根又重新指向此对象。那么此对象又成了可到达的对象,不会被垃圾收集器收集,但是此对象的引用未被加入结束队列中。所以此处需要用ReRegisterForFinalize方法来将对象的引用添加到结束队列中。因为重生本身在现实应用中就很少见,所以ReRegisterForFinalize也将比较少用到。

垃圾收集器内部有一个长弱引用表,用这样声明的弱引用对象将不会在托管堆中分配空间,而是在长弱引用表中分配一个槽。此槽中记录对myAnotherObject的引用。New操作将此槽的地址返回给myLongWeakReferenceObject变量。

Garbage Collector Basics and Performance Hints By Rico Mariani at Microsoft 

Because the objects with Finalize method will be appended to Finalization queue when new operation, there are few scenarios to use ReRegisterForFinalize method. A typical scenario is to use ReRegisterForFinalize with Resurrection. Resurrection is that we let a root point to the object again in Finalize method, and then the object becomes reachable again, therefore it will be not collected by garbage collector. But the reference of the object has not been appended to Finalization queue, therefore we can use ReRegisterForFinalize to append the object to Finalization queue. Because there are few requirement in reality to use resurrection, ReRegisterForFinalize will be used in low rate.

Garbage collector has a long weak reference table inside, the weak reference object declared in such a way will not allocate space from managed heap, and a slot will be allocated in the long weak reference table for the weak reference object. The slot records the referene of myAnotherObject. New operation returns the address of the slot to myLongWeakReferenceObject variable.

相比之下,SuppressFinalize更常用些。SuppressFinalize用于同时实现了Finalize方法和Dispose()方法来释放资源的情况下。在Dispose()方法中调用GC.SuppressFinalize(this),那么CLR就不会执行Finalize方法。Finalize方法是程序员忘记用Close或者Dispose等方法清理资源时的一个保证措施。如果程序员记得调用Dispose(),那么就会不执行Finalize()来再次释放资源;如果程序员忘记调用Dispose(), Finalize方法将是最后一个保证资源释放的措施。这样做不失为一种双保险的方案。

垃圾收集器此时的收集流程是这样的: The collecting process of garbage collector in this scenario is looking like the follwoing:

 

Comparing to ReRegisterForFinalize, SuppressFinalize has more frequent utilization. When we implement both Finalize method and Dispose method to release resources, we need to use SuppressFinalize method. Call GC.SuppressFinalize(this) in the body of Dispose() method and then CLR will not execute the Finalize method. Finalization is an ensuring mechanism when programmers forget to use Close or Dispose method to clean up resources. If programmers do call Dispose(), then CLR will not call Finalize method to release resources again. If programmers forget to call Dispose(), then Finalize method will be the final ensuring mechnism for resource releasing. That way it is a dual fail-safe solution.

1. 垃圾收集器建立对象引用图,来找到所有的可到达对象。前文已经说过如何建立图。特别的地方是,如果遇到非WeakReference指针,就加入图,如果遇到WeakReference指针,就不加入图。这样图就建好了。Garbage collector builds up the reference ralationship graph to find all the reachable objects. The way to build up the graph is mentioned earlier. The special space is, if encounters a non-WeakReference pointer, then appends it to the graph, if meets a WeakReference pointer, then does not append it to the graph. The graph is built in this way.

装扮小游戏 换装小游戏 化妆小游戏 美女小游戏 古装公主小游戏 装扮仙女小游戏 装扮男友小游戏 情侣约会小游戏 婚纱礼服小游戏 阿sue小游戏 做饭小游戏 美女餐厅小游戏 理发小游戏 美甲小游戏 芭比娃娃小游戏 大头妹小游戏 布置房间小游戏 照顾宝宝小游戏 祖玛小游戏 连连看小游戏 对对碰小游戏 泡泡堂小游戏 超级玛丽小游戏 黄金矿工小游戏 密室逃脱小游戏 魔塔小游戏 找茬小游戏 发泄小游戏 双人小游戏 儿童小游戏 奥特曼小游戏 海绵宝宝小游戏 虹猫蓝兔小游戏 哆啦A梦小游戏 喜羊羊与灰太狼小游戏 搞笑小游戏 休闲小游戏 冒险小游戏 模拟经营小游戏 棋牌小游戏 测试小游戏 策略小游戏 动作小游戏 体育小游戏 敏捷小游戏 射击小游戏 益智小游戏 综合小游戏

对象结束机制对垃圾收集器的性能影响比较大,同时CLR难以保证调用Finalize方法的时间和次序。因此,尽量不要用对象结束机制,而采用自定义的方法或者名为Close, Dispose的方法来清理资源。可以考虑实现IDisposable接口并为Dispose方法写好清理资源的方法体。

2. 垃圾收集器扫描短弱引用表。如果一个指针指向一个不在图中的对象,那么此对象就是一个不可到达的对象,垃圾收集器就将短弱引用表相应的槽置空。Garbage collector scans the short weak reference table. If a pointer pointing to an object not in the graph, then the object is not a reachable object, and then garbage collector sets the slot to null in the short weak reference table.

Finalization has significant impact on performance of garbage collector, and CLR can not be sure on the time and order to call Finalize methods of objects, therefore please do not use finalization of objects as possible as you can, instead, you could use self defined methods, Close method or Dispose method to clean up resources. Please think about to implement the IDisposable interface and write method body for the Dispose method to clean up resources.

3. 垃圾收集器扫描结束队列。如果队列中一个指针指向一个不在图中的对象,此指针将被从结束队列移到待结束队列,同时此对象被加入引用关系图中,因为此时此对象是Finalize可到达的。Garbage collector scans the Finalization queue. If a pointer in the queue pointing to an ojbect not in the graph, then the pointer will be moved to the ToBeFinalized queue, and the object will be appended to the reference relationship graph, because the object is Finalize reachable at this time.

大对象堆Large object heap
大对象堆专用于存放大于85000字节的对象。初始的大对象内存区域堆通常在第0代内存之上,并且与第0代内存不邻接。第0,第1和第2代合起来称为小对象堆。CLR分配一个新的对象时,如果其大小小于85000字节,就在第0代中分配,如果其大小大于等于85000自己,就在大对象堆中分配。

4. 垃圾收集器扫描长弱引用表。如果一个指针指向一个不在图中的对象(注意此时图中已包含Finalize可到达的对象),那么此对象就是一个不可到达的对象,垃圾收集器就将长弱引用表相应的槽置空。Garbage collector scans the long weak reference table. If a pointer pointing to an object not in the graph, then the object is not a reachable object, and then garbage collector sets the slot to null in the long weak reference table.

Large object heap is to store objects that its size is over 85000 bytes. The initial memory block of large object heap is above the memory block of generation 0, and it is not adjacent to memory block of generation 0. Generation 0,1 and 2 is called small object heap. When CLR allocates a new object, if its size is lower than 85000 bytes, then allocates memory in generation 0; If its size is over 85000 bytes, then allocates memory in large object heap.

  1. 垃圾收集器夯实(压缩)托管堆。 Garbage collector tamps(or compacts) the managed heap.
    短弱引用不跟踪重生。即垃圾收集器发现一个对象为不可到达就立即将短弱引用表相应的槽置空。如果该对象有Finalize方法,并且Finalize方法还没有执行,所以该对象就还存在。如果应用程序访问弱引用对象的Target属性,即使该对象还存在,也会得到null。

因为大对象的尺寸比较大,收集时成本比较高,所以对大对象的收集是在第2代收集时。大对象的收集也是从根开始查找可到达对象,那些不可到达的大对象就可回收。垃圾收集器回收了大对象后,不会对大对象堆进行夯实操作(毕竟移动大对象成本较高),而是用一个空闲对象表的数据结构来登记哪些对象的空间可以再利用,其中两个相邻的大对象回收将在空闲对象表中作为一个对象对待。空闲对象表登记的空间将可以再分配新的大对象。

Short weak reference does not track resurrection. It means that garbage collector sets the slot to null in the short weak reference table as soon as finds an object not reachable. If the object has a Finalize method, and its Finalize method has not been executed, then the object still exists. If the applicaiton accesses the Target property of the weak referene object, and gets null even though the object still exists.

Because size of large object is significant, the cost of collection is significant also. Collection of large objects happens when collecting generation 2.  Collection of large objects starts from the roots also and searches for reachable objects. Non-reachable large objects will be collected. After collecting non-reachable large objects, garbage collector will not tamp the large object heap(because the cost of moving a large object is high), instead, garbage collector uses a free object table to record memory ranges that can be re-used, if there are two adjacent large object collected, then treats the two large objects as one large object in free object table. The memory ranges in free object table can be re-used by new large objects.

长弱引用跟踪重生。即垃圾收集器发现一个对象是Finalize可到达的对象,就不将相应的槽置空。因为Finalize方法还没有执行,所以该对象就还存在。如果应用程序访问弱引用对象的Target属性,可以得到该对象;但是如果Finalize方法已经被执行,就表明该对象没有重生。

大对象的分配,回收的成本都较小对象高,因此在实践中最好避免很快地分配大对象又很快回收,可以考虑如何分配一个大对象池,重复利用这个大对象池,而不频繁地回收。

Long weak reference tracks resurrection. It means that garbage collector does not set the slot to null in the long weak reference table when garbage collector  meets an object is Finalize reachable. Because the Finalize method has not been executed, the object still exists. If the application accesses the Target property of the weak reference object, and gets the object. But if the Finalize method has been executed, then the object is not resurrected.

The cost of allocation and collection of large objects is higher than the cost of allocation and collection of small objects, therefore it would better avoid to allocate large object and release it soon. Please think about allocate a pool of large objects, try to re-use the pool of large objects, do not frequently reclaim large objects.

按照上面的例子,如果执行如下代码会发生什么呢?Continue the above example, what will happen if we execute the following code?

未完待续To be continued…

//File: MyClass.cs
using System;
using System.Collections.Generic;
using System.Text;

参考文献References

namespace ConsoleApplication2

Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework By Jeffrey Richter 

美女小游戏打分装扮小游戏 古装公主小游戏 装扮仙女小游戏 装扮男友小游戏 婚纱礼服小游戏 大头妹小游戏 芭比娃娃小游戏 布置房间小游戏 照顾宝宝小游戏 心理测试小游戏 连连看 对对碰 找不同 泡泡堂 祖玛 超级玛丽 黄金矿工

Garbage Collection Part 2: Automatic Memory Management in the Microsoft .NET Framework By Jeffrey Richter

{
    class MyClass
    {
        ~MyClass()
        {
            Console.WriteLine("In MyClass destructor+++++++++++++++++++++++++++");
        }
    }
}//File: MyAnotherClass.cs
using System;
using System.Collections.Generic;
using System.Text;

Garbage Collector Basics and Performance Hints By Rico Mariani at Microsoft 

 

namespace ConsoleApplication2
{
    public class MyAnotherClass
    {
        ~MyAnotherClass()
        {
            Console.WriteLine("In MyAnotherClass destructor___________________________________");
        }
    }
}//File: Program.cs
using System;
using System.Collections.Generic;
using System.Text;

Large Object Heap Uncovered By Maoni Stephens

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass myClass = new MyClass();
            MyAnotherClass myAnotherClass = new MyAnotherClass();
            WeakReference myShortWeakReferenceObject = new WeakReference(myClass);
            WeakReference myLongWeakReferenceObject = new WeakReference(myAnotherClass, true);
            Console.WriteLine("Release managed resources by setting locals to null.");
            myClass = null;
            myAnotherClass = null;

Garbage collection in msdn

            Console.WriteLine("Check whether the objects are still alive.");
            CheckStatus(myShortWeakReferenceObject, "myClass ", "myShortWeakReferenceObject");
            CheckStatus(myLongWeakReferenceObject, "myAnotherClass", "myLongWeakReferenceObject");

 

            Console.WriteLine("Programmatically cause GC.");
            GC.Collect();

装扮小游戏 换装小游戏 化妆小游戏 美女小游戏 古装公主小游戏 装扮仙女小游戏 装扮男友小游戏 情侣约会小游戏 婚纱礼服小游戏 阿sue小游戏 做饭小游戏 美女餐厅小游戏 理发小游戏 美甲小游戏 芭比娃娃小游戏 大头妹小游戏 布置房间小游戏 照顾宝宝小游戏 祖玛小游戏 连连看小游戏 对对碰小游戏 泡泡堂小游戏 超级玛丽小游戏 黄金矿工小游戏 密室逃脱小游戏 魔塔小游戏 找茬小游戏 发泄小游戏 双人小游戏

            Console.WriteLine("Wait for GC runs the finalization methods.");
            GC.WaitForPendingFinalizers();

            //Check whether the objects are still alive.
            CheckStatus(myShortWeakReferenceObject, "myClass ", "myShortWeakReferenceObject");
            CheckStatus(myLongWeakReferenceObject, "myAnotherClass", "myLongWeakReferenceObject");

编辑:儿童文学 本文来源:0对垃圾回收机制的改进2,0垃圾回收机制的改进

关键词:

  • 上一篇:没有了
  • 下一篇:没有了