.NET:CLR via C#The Managed Heap and Garbage Collection
Allocating Resources from the Managed Heap
The CLR requires that all objects be allocated from the managed heap. When a process is initialized, the CLR allocates a region of address space for the managed heap. The CLR also maintains a pointer, which I’ll call NextObjPtr. This pointer indicates where the next object is to be allocated within the heap. Initially, NextObjPtr is set to the base address of the address space region.
C#’s new operator causes the CLR to perform the following steps:
- Calculate the number of bytes required for the type’s fields (and all the fields it inherits from its base types).
 - Add the bytes required for an object’s overhead. Each object has two overhead fields: a type object pointer and a sync block index. For a 32-bit application, each of these fields requires CHAPTER 21 The Managed Heap and Garbage Collection 507 32 bits, adding 8 bytes to each object. For a 64-bit application, each field is 64 bits, adding 16 bytes to each object.
 - The CLR then checks that the bytes required to allocate the object are available in the region. If there is enough free space in the managed heap, the object will fit, starting at the address pointed to by NextObjPtr, and these bytes are zeroed out. The type’s constructor is called (passing NextObjPtr for the this parameter), and the new operator returns a reference to the object. Just before the reference is returned, NextObjPtr is advanced past the object and now points to the address where the next object will be placed in the heap.
 
The Garbage Collection Algorithm
the CLR uses a referencing tracking algorithm. The reference tracking algorithm cares only about reference type variables, because only these variables can refer to an object on the heap; value type variables contain the value type instance directly. Reference type variables can be used in many contexts: static and instance fields within a class or a method’s arguments or local variables. We refer to all reference type variables as roots.
When the CLR starts a GC, the CLR first suspends all threads in the process. This prevents threads from accessing objects and changing their state while the CLR examines them. Then, the CLR performs what is called the marking phase of the GC. First, it walks through all the objects in the heap setting a bit (contained in the sync block index field) to 0. This indicates that all objects should be deleted. Then, the CLR looks at all active roots to see which objects they refer to. This is what makes the CLR’s GC a reference tracking GC. If a root contains null, the CLR ignores the root and moves on to examine the next root.
Any root referring to an object on the heap causes the CLR to mark that object. Marking an object means that the CLR sets the bit in the object’s sync block index to 1. When an object is marked, the CLR examines the roots inside that object and marks the objects they refer to. If the CLR is about to mark an already-marked object, then it does not examine the object’s fields again. This prevents an infinite loop from occurring in the case where you have a circular reference.
The marking phase continues until all the application roots have been examined
Once complete, the heap contains some marked and some unmarked objects. The marked objects must survive the collection because there is at least one root that refers to the object; we say that the object is reachable because application code can reach (or access) the object by way of the variable that still refers to it. Unmarked objects are unreachable because there is no root existing in the application that would allow for the object to ever be accessed again.
Now that the CLR knows which objects must survive and which objects can be deleted, it begins the GC’s compacting phase. During the compacting phase, the CLR shifts the memory consumed by the marked objects down in the heap, compacting all the surviving objects together so that they are contiguous in memory. This serves many benefits. First, all the surviving objects will be next to each other in memory; this restores locality of reference reducing your application’s working set size, thereby improving the performance of accessing these objects in the future. Second, the free space is all contiguous as well, so this region of address space can be freed, allowing other things to use it. Finally, compaction means that there are no address space fragmentation issues with the managed heap as is known to happen with native heaps.
When compacting memory, the CLR is moving objects around in memory. This is a problem because any root that referred to a surviving object now refers to where that object was in memory; not where the object has been relocated to. When the application’s threads eventually get resumed, they would access the old memory locations and corrupt memory. Clearly, this can’t be allowed and so, as part of the compacting phase, the CLR subtracts from each root the number of bytes that the object it referred to was shifted down in memory. This ensures that every root refers to the same object it did before; it’s just that the object is at a different location in memory.
After the heap memory is compacted, the managed heap’s NextObjPtr pointer is set to point to a location just after the last surviving object. This is where the next allocated object will be placed in memory.
Generations: Improving Performance
A generational GC makes the following assumptions about your code:
- The newer an object is, the shorter its lifetime will be.
 - The older an object is, the longer its lifetime will be.
 - Collecting a portion of the heap is faster than collecting the whole heap.
 
When initialized, the managed heap contains no objects. Objects added to the heap are said to be in generation 0. Stated simply, objects in generation 0 are newly constructed objects that the garbage collector has never examined.
When the CLR initializes, it selects a budget size (in kilobytes) for generation 0. So if allocating a new object causes generation 0 to surpass its budget, a garbage collection must start.
The objects that survive the garbage collection are said to be in generation 1.
After a garbage collection, generation 0 contains no objects. As always, new objects will be allocated in generation 0.
when the CLR initializes, it selects a budget for generation 0. Well, it also selects a budget for generation 1.
When starting a garbage collection, the garbage collector also sees how much memory is occupied by generation 1. In this case, generation 1 occupies much less than its budget, so the garbage collector examines only the objects in generation 0. Look again at the assumptions that the generational garbage collector makes. The first assumption is that newly created objects have a short lifetime. So generation 0 is likely to have a lot of garbage in it, and collecting generation 0 will therefore reclaim a lot of memory. The garbage collector will just ignore the objects in generation 1, which will speed up the garbage collection process.
the garbage collector sees that the objects in generation 1 are occupying so much memory that generation 1’s budget has been reached. Over the several generation 0 collections, it’s likely that a number of objects in generation 1 have become unreachable (as in our example). So this time, the garbage collector decides to examine all of the objects in generation 1 and generation 0.
After four collections: generation 1 survivors are promoted to generation 2, generation 0 survivors are promoted to generation 1, and generation 0 is empty.
As before, any objects that were in generation 0 that survived the garbage collection are now in generation 1; any objects that were in generation 1 that survived the collection are now in generation 2. As always, generation 0 is empty immediately after a garbage collection and is where new objects will be allocated. Objects in generation 2 are objects that the garbage collector has examined two or more times. There might have been several collections, but the objects in generation 1 are examined only when generation 1 reaches its budget, which usually requires several garbage collections of generation 0.
The managed heap supports only three generations: generation 0, generation 1, and generation 2; there is no generation 3.3
Garbage Collection Triggers
- Code explicitly calls System.GC’s static Collect method
 - Windows is reporting low memory conditions
 - The CLR is unloading an AppDomain
 - The CLR is shutting down
 
Large Objects
There is one more performance improvement you might want to be aware of. The CLR considers each single object to be either a small object or a large object. Today, a large object is 85,000 bytes or more in size.4 The CLR treats large objects slightly differently than how it treats small objects:
- Large objects are not allocated within the same address space as small objects; they are allocated elsewhere within the process’ address space.
 - Today, the GC doesn’t compact large objects because of the time it would require to move them in memory. For this reason, address space fragmentation can occur between large objects within the process leading to an OutOfMemoryException being thrown. In a future version of the CLR, large objects may participate in compaction.
 - Large objects are immediately considered to be part of generation 2; they are never in generation 0 or 1. So, you should create large objects only for resources that you need to keep alive for a long time. Allocating short-lived large objects will cause generation 2 to be collected more frequently, hurting performance. Usually large objects are large strings (like XML or JSON) or byte arrays that you use for I/O operations, such as reading bytes from a file or network into a buffer so you can process it.
 
.NET:CLR via C#The Managed Heap and Garbage Collection的更多相关文章
- Advanced .NET Debugging: Managed Heap and Garbage Collection(转载,托管堆查内存碎片问题解决思路)
		
原文地址:http://www.informit.com/articles/article.aspx?p=1409801&seqNum=4 Debugging Managed Heap Fra ...
 - Understanding the managed heap
		
Understanding the managed heap Another common problem faced by many Unity developers is the unexpe ...
 - Windbg Extension NetExt 使用指南 【3】 ---- 挖掘你想要的数据 Managed Heap
		
摘要 : NetExt中有两个比较常用的命令可以用来分析heap上面的对象. 一个是!wheap, 另外一个是!windex. !wheap 这个命令可以用于打印出heap structure信息. ...
 - .NET:CLR via C#:CLR Hosting And AppDomains
		
AppDomain Unloading To unload an AppDomain, you call AppDomain’s Unload static method.This call caus ...
 - 从ASP.NET Core 3.0 preview 特性,了解CLR的Garbage Collection
		
前言 在阅读这篇文章:Announcing Net Core 3 Preview3的时候,我看到了这样一个特性: Docker and cgroup memory Limits We conclude ...
 - JVM学习二:垃圾收集(Garbage Collection,GC)机制
		
JVM的GC分为两个主要部分,第一部分是判断对象是否已死(堆内存的垃圾回收占主要部分,方法区(metaspace)的内存回收在最新的官方文档中未给出详细解释,暂时不做讨论范围),第二部分是对内存区进行 ...
 - [转] 分代垃圾回收的 新旧代引用问题(原标题:Back To Basics: Generational Garbage Collection)
		
原文链接: https://blogs.msdn.microsoft.com/abhinaba/2009/03/02/back-to-basics-generational-garbage-colle ...
 - ssh框架错误:org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role。
		
在做ssh项目练习的时候出现问题: org.hibernate.LazyInitializationException: failed to lazily initialize a collectio ...
 - CLR via C#读书笔记一:CLR的执行模型
		
CLR(Common Language Runtime)公共语言进行时是一个可由多种编程语言使用的“进行时”. 将源代码编译成托管模块 可用支持CLR的任何语言创建源代码文件,然后用对应的编译器检查语 ...
 
随机推荐
- 《HBase实战》学习笔记
			
第二章 入门 HBase写路径: 增加新行和修改已有的行,内部机制是一样的. 写入的时候,会写到预写日志(WAL)和MemStore中. MenmStore是内存里的写入缓冲区.填满后,会将数据刷写 ...
 - CCF CSP 201403-3 命令行选项
			
CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201403-3 命令行选项 问题描述 请你写一个命令行分析程序,用以分析给定的命令行里包含哪些 ...
 - NPOI 读取单元格的格式
			
最近做项目需要导入一部分数据, 导入的数据的中, 有部分的百分比数据使用的是excel 的百分比, 有部分的数据使用的是字符串形式的格式,(数据来源于不同的人统计), 格式略微有点乱, 要求导入系统的 ...
 - 基于 SSH 框架的 Criteria 和 DetachedCriteria 多条件查询
			
Hibernate 定义了 CriteriaSpecification 接口规范用来完成面向对象的条件查询,Criteria 和 DetachedCriteria 就是 CriteriaSpecifi ...
 - MySQL用户授权 和 bin-log日志 详解和实战
			
看了上一篇博文的发布时间,到目前已经有三个月没更新博文了.这三个月经历了很多事情,包括工作.生活和感情等等.由于个人发展的原因,这个月准备换工作啦.在这段时间,我会把Web大型项目中所接触到的技术都总 ...
 - 【原创】MySQL常用脚本整理
			
#1.查看表容量空间 ) ) ) AS 'free_size(G)' FROM information_schema.tables WHERE TABLE_SCHEMA='test' AND TABL ...
 - Could not open JDBC Connection for transaction; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (Could not create connection to database server.
			
报错信息:Could not open JDBC Connection for transaction; nested exception is org.apache.commons.dbcp.SQL ...
 - jQuery记忆巩固
			
jQuery是由原生js写的所以说所有jQuery制作出来的效果都可以使用js做出来,jQuery出现的目的是为了优化代码,提高码代码的效率它将很多功能封装. 一.jQuery的认识 1.何为jque ...
 - 【BZOJ 2688】 2688: Green Hackenbush (概率DP+博弈-树上删边)
			
2688: Green Hackenbush Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 42 Solved: 16 Description ...
 - java集合之一(框架介绍)
			
本文转载自:http://www.cnblogs.com/skywang12345/p/3308498.html Java集合主要可以划分为4个部分:List列表.Set集合.Map映射.工具类(It ...