.NET CLR如何区分托管与非托管指针?

Meh*_*dad 10 .net clr garbage-collection

所有东西最终都被嵌入到本机机器代码中,因此最终,我们在.NET中有一个本机堆栈,只要它进行垃圾收集,GC就需要扫描对象指针.

现在,问题是:.NET垃圾收集器如何确定指向GC堆内对象的指针实际上是托管指针还是碰巧具有与有效地址对应的值的随机整数?

显然,如果它无法区分这两者,那么可能存在内存泄漏,所以我想知道它是如何工作的.或者 - 我敢说 - .NET有可能泄漏内存吗?:o

Eri*_*ert 12

正如其他人所指出的那样,GC确切地知道堆栈和堆上每个块的哪些字段是托管引用,因为GC和抖动知道所有内容的类型.

但是,你的观点很好.想象一个完全假设的世界,在同一个过程中有两种内存管理.例如,假设你有一个用C++编写的名为"InterMothra Chro-Nagava-Sploranator"的假设程序,该程序使用传统的COM样式引用计数内存管理,其中一切只是指向进程内存的指针,并且通过调用一个对象来释放对象.释放方法正确次数.假设Sploranator假设有一种脚本语言JabbaScript,它维护一个垃圾收集的对象池.

当JabbaScript对象具有对非托管Sploranator对象的引用,并且该Sploranator对象具有右引用时,会出现问题.这是一个循环引用,不能被JabbaScript垃圾收集器破坏,因为它不知道Sploranator对象的内存布局.因此存在内存泄漏的可能性.

解决此问题的一种方法是重写Sploranator内存管理器,以便将其对象分配到托管GC池之外.

另一种方法是使用启发式方法; GC可以专门处理一个处理器的线程来扫描所有内存,寻找恰好是指向其对象的指针的整数.这听起来很多,但它可以省略未提交的页面,自己的托管堆中的页面,已知仅包含代码的页面等等.GC可以猜测,如果它认为一个对象可能已经死了,并且它无法在其控制之外的任何内存中找到任何指向该对象的指针,那么该对象几乎肯定已经死了.

这种启发式的缺点当然是错误的.您可能有一个意外匹配指针的整数(虽然这在64位域中不太可能).这将延长对象的生命周期.但谁在乎?我们已经处于循环引用可以延长对象生命周期的情况.我们试图让这种情况变得更好,而这种启发式方法也是如此.它不完美是无关紧要的; 它总比没有好.

另一种可能是错误的方式是Sploranator可以对指针进行编码,比如说,在存储值时翻转它的所有位,只在调用之前将其翻转回来.如果Sploranator 对此GC启发式策略有积极的敌意,那么它就不起作用.

这里概述的垃圾收集策略与任何产品的实际GC策略之间的相似性几乎完全是巧合.Eric关于假设的不存在产品的垃圾收集器的实施细节的思考仅用于娱乐目的.

  • 想象一下当GC在堆压缩时更新整数(认为它是指针)时会发生什么 (2认同)