目录
抽象语言特征学术探讨
垃圾收集器怀疑论
.NET中的垃圾收集器——成熟阶段
.NET中的垃圾收集器——分代和启发式
GC暂停和延迟
调整GC
编写“GC友好”程序
微软的GC性能提示——不切实际
重用对象的建议
Roslyn编码约定
.NET Framework中GC的实际问题
大规模.NET应用程序中的延迟
GC暂停和延迟
.NET Framework中GC的现状
.NET Framework的替代内存管理策略
注:GCD被发现是未完成的研究
带删除的垃圾收集(GCD)(*)
GCD解决方案的好处
GCD框架中的编程风格
从GC到GCD框架的过渡
支持GCD框架所需的工具
Microsoft在.NET中试验非托管堆(***)
对这么大的框架.NET进行如此重大的改变是否现实?
结论
参考
抽象语言特征学术探讨首先,可以讨论对任何编程语言或框架(包括C#和.NET)的可能更改或增强。虽然C#和.NET是Microsoft的产品,并且由那里的一些产品经理负责和授权决定C#和.NET的发展方向,但我们可以从计算机科学的角度自由讨论,将其视为只有一种抽象编程语言概念的实现。因此,当我们在这里谈论C#时,我们正在考虑一些“类似C#的抽象语言”,我们并不关心讨论的功能是否会包含在特定产品中。
当我在下文中谈到“.NET框架”时,我指的是一般意义上的框架,包括“.NET Framework”、“.NET Core”、“.NET”和“Mono”等所有家庭成员。
软件工程是一门工程学科,它从现实世界的工程问题中获得灵感和驱动,讨论它们,并尝试在抽象的层面上改进和解决它们,并在一些新一代产品中得到解决。这里讨论的原则大部分将适用于Java语言,或者可以适用于一些未来的、仍然不存在的计算机语言或框架。因此,请将此视为有关该主题的学术讨论。
垃圾收集器怀疑论甚至当我第一次了解Java语言的垃圾收集器技术时,我就已经是一个“GC怀疑论者”了。
的确,它一开始就解决了我们在一些C/C++产品中遇到的内存泄漏问题,我一直在寻找这个问题,并使用了所有可能的工具,例如Purify [5]和BoundChecker[6]。但是,作为一名训练有素的数学家,我立即感觉到在垃圾收集中,与“图遍历问题”[7]有相似之处,并且遍历的复杂性可能很大。如果您有一个勤劳的线程创建对象图(需要遍历)和另一个线程正在遍历创建的对象图(为了垃圾收集的目的),如果第一个线程需要1个时间单位,则很容易发生创建一些复杂的图,第二个线程可能需要10个单位的时间来遍历它,以达到垃圾收集的目的。所以,垃圾收集技术从一开始就很明显会有一些局限性。
但事实是线程并不是一直在创建新的对象图,它们也在做其他事情。所以,垃圾收集技术就在这里,它是可用的,它正在解决一个巨大的内存泄漏问题,但让我们看看它在广泛的应用程序中的实用性。
.NET中的垃圾收集器——成熟阶段.NET Framework/.NET Core现在是一项已有20年历史的技术。从它的第一个版本开始,它就包含了垃圾收集器技术。我认为我们可以自由地说,GC技术正处于其顶峰。多年来,我敢肯定,许多科学家和工程师都致力于开发和改进GC技术。在未来几年,在不远的将来,极不可能出现一些根本性的突破,从而显着改进GC技术。可能会对启发式规则进行一些调整,以适应不断改进的硬件、更多的CPU能力和更多的RAM,但我们现在拥有的关于GC技术的东西是我们未来几年所锁定的。
.NET中的垃圾收集器——分代和启发式在[1]中,概述了.NET垃圾收集器的体系结构。在这里,我们只提一下,多年来工程师们能够提出的最佳解决方案是使其“代代相传”,这本身已经是一种启发式方法。
他们使GC分代的原因是因为“每次都进行完整的垃圾收集太昂贵了”([1])。只有一个“常识”的论点,即“在一个GC周期中存活”的对象需要不那么频繁地检查清理,并且可以移动到上面的一代。没有科学/数学算法来支持这一点。创建一个完全相反的程序会很容易。此外,以85KB的限制将“对象分为大小对象”([9])并将它们保存在一个大对象堆(LOH)中再次只是另一种启发式方法。他们这样做的原因是希望更快地压缩内存或减少压缩内存。
我之所以强调GC架构的许多元素都是启发式的,而不是基于算法/可证明的,是因为后果。结果是启发式GC策略在某些情况下可能并且将会失败,这意味着对于某些C#/.NET程序,GC的性能会很差。
GC暂停和延迟最新版本的GC有2种类型的集合:1)Foreground;2)Background([12],[13])。Foreground GC适用于Gen0和Gen1,而Background仅适用于Gen2。当Foreground垃圾回收发生时,所有托管线程都被挂起。Background GC使托管线程能够在垃圾回收期间继续操作。对于许多应用程序来说,定期冻结所有线程是个坏消息,因此GC可以完成它的工作。问题当然是应用程序线程将被挂起的频率和时间。在您的应用程序中使用GC的实际结果是延迟,这是不可避免的。
调整GC可以“调整” GC,将其应用于您的应用程序。您可以选择“低延迟”模式 ([14]),其中Gen2的集合被抑制/限制,而Gen0和Gen1的集合仍然继续。此外,还有许多配置选项([11])可以让您影响GC的工作方式。但我认为期望程序员花时间调整每个应用程序的GC参数是不现实的。当然,如果您有时间的话,调整/配置GC的认真方法包括使用一些高级内存监控工具进行一些测试试验校正工作。
话虽如此,.NET GC技术是许多工程师经过20年研究后能够提出的最好的技术。
编写“GC友好”程序随着垃圾收集器技术的到来,出现了一个巨大的运动,要求程序员改变他们的风格并编写他们的程序,以便他们与GC“合作”,或者说是“GC友好”。我有点怀疑,因为GC技术被宣传为让程序员更轻松,并且在后台透明地工作。现在,您突然要求程序员付出额外的努力,以“适应”GC的风格编写程序。一方面,您将程序员从考虑内存释放的需要中解放出来,但另一方面,您给了他们另一个任务,据说更容易,应用将适应垃圾收集的模式。
让我们来看看其中的一些建议。
微软的GC性能提示——不切实际在[1]中,有一个Microsoft自己的关于如何在存在GC的情况下进行编程的建议列表。他们列出,引用他们的话:“为了让收集器发挥最佳性能,我们应该尽量避免一些事情”
- (避免)过多的分配——这几乎是个有趣的建议。没有人只是为了好玩而分配对象。程序员分配变量/对象是因为程序逻辑需要它,而在严肃的程序中,它们会很多。正如他们所说,这几乎是“不要过多地使用内存,所以我们好的GC不需要努力工作”。
- (避免)太大的分配——再一次,荒谬的建议。我有一台32GB RAM的笔记本电脑,你告诉我不要创建大对象。我猜GC的问题是压缩堆并且在大对象周围移动非常耗时。但是,如果我不大量使用这些内存,那又有什么意义呢?
- (避免)太多的指针——我看到很多指针/引用意味着复杂的图形对象,遍历复杂的图形非常耗时。但是,如果您的业务逻辑是科学/工程的,那么您的对象图可能会变得非常复杂。这是不切实际的建议。
- (避免)太多对象写入——同样,它们暗示你的程序逻辑/业务领域隐含算法应该是什么样子。如果您需要经常更改对象状态,就是这样。否则程序将无法实现其主要目的。
- (避免)太多几乎长寿命的对象——同样,我有32GB的内存,如果我的程序逻辑需要,我不想被告知不要在我的内存中保留很多对象。
- (避免)Finalization ——这是一个语言特性,是为了一个好的目的而存在的。如果它在那里,为什么要限制它的使用。
从一个有趣的角度来看上面的建议,几乎就像他们说的那样:“不要创建太复杂、太复杂、太大的程序,这样我们的好GC可以快速运行”。但说真的,程序员在解决问题时会考虑很多其他事情,因此根本不欢迎额外的“对GC友好”会影响他们的程序逻辑/算法的请求。
重用对象的建议有很多建议“重用”分配的对象,以避免重新分配。甚至还有一些模式,比如“对象池模式”[15]。首先,它再次给程序员带来了改变程序逻辑并为他们创建额外工作的负担,例如重置对象的状态、池化对象等。有时,这并不现实,您只需要创建新对象即可就是这样。
Roslyn编码约定在[3]中是对Rosalyn项目的一些建议:“通常Roslyn中的性能提升归结为一件事:确保垃圾收集器完成尽可能少的工作”。因此,它隐含地认识到GC延迟是与性能相关的主要问题。
列出的建议是:
- 避免使用LINQ。
- 避免在没有struct枚举器的集合上使用foreach。
- 考虑使用对象池。编译器中有很多对象池的用法,看一个例子。
同样,它限制了程序员使用哪些技术/技术,所有这些都只是为了适应GC并最大限度地减少其延迟。此外,避免堆上的对象/结构并仅使用堆栈上的对象/结构表明托管堆的解决方案存在问题。
.NET Framework中GC的实际问题在这里,我们将列举一些与使用GC技术相关的问题示例
大规模.NET应用程序中的延迟在[2]中,有一个很好的例子,正如他们所说,“与.NET GC战斗”。我将在这里列出作者的结论:
- 这些天剩余的延迟主要与GC相关,但是,它们比过去要短得多。
- 如果您在大规模.NET应用程序中遇到类似问题……您可以用C++重写组件
最后一个建议,使用C++语言重写部分代码,有点质疑.NET GC对大规模应用程序的适用性。
GC暂停和延迟已被广泛认可和测量([4]),GC给应用程序带来了显着的延迟,这是由于应用程序线程暂停期间导致的,因此GC可以完成其工作。
.NET Framework中GC的现状在这里,我们将批评GC技术作为.NET框架的一部分。多年来,GC技术是.NET框架的“圣牛”,没有人会说它坏话。这并不是真正的“Down with GC”类型的文本,而更像是“GC很好,但并非总是如此”。以下是我的拙见。
- GC技术适用于许多C#应用程序,尤其是中小型复杂性/规模项目
- 但是很多C#应用程序的GC技术,特别是高复杂度/大尺寸,产生了许多延迟问题,并且未能成为有效的内存管理策略
- 通过要求程序员编写“对GC友好的代码”,责任和工作负担从.NET Framework推到了单个程序员身上。在某种程度上,这是不公平的,因为现在程序员要对GC技术的局限性以及在.NET框架中使用它的选择负责,这是强加给他们的。更糟糕的是,即使他们遵循所有这些建议与GC合作,仍然无法保证能够成功避免GC引起的延迟等(参见 [2])。另外,让我们记住,GC的主要目的是简化程序员的工作并使他们更容易工作,而不是创建额外的任务来取代现在简单地清理/释放已使用变量/对象的内存的原始任务。许多程序员仍然能够自行释放内存,只要他们选择的语言有适当的API。
- 不要因为谈论GC技术而被催眠,比如“第0代、大对象堆等”。这绝对是一个伟大而聪明的技术方案,但经过20年的发展,它已经达到了顶峰,可以说它有严重的局限性,并不是一个适用于每个案例和每个应用场景的好方案。我个人喜欢使用它并重视它,但有时希望可以选择使用其他东西。
- 问题是.NET Framework提供GC作为最终且唯一的内存管理解决方案。使用C#语言的程序员没有选择决定例如使用非托管堆,他们将接管自己释放内存的责任,而他们可能完全胜任。(在这里,我们排除了类似AllocHGlobal和类似的API的使用,因为它们没有集成到C#语言中,您可以轻松地使用类似NewUnmanagedHeap(..type..)的东西分配对象)。
- .NET Framework将自己锁定为仅GC作为内存管理解决方案所做出的选择,具有严重的局限性,使其继承了这些局限性。实际结果是.NET Framework,由于其局限性,可能不是每种应用场景的最佳语言/框架选择。对于.NET Framework来说,这是一个严重的问题,它的雄心是成为“世界上最好、最快的编程框架……?”
- 最大的障碍是多年来开发的许多C#/.NET库和应用程序框架都基于GC技术。即使我们在C#语言中添加NewUnmanagedHeap(..type..)/ DeleteUnmangedHeap(..object..)之类的内容,您将在主应用程序主体中使用它,您仍然会受到库中使用的已分配对象创建的GC暂停的影响。
- 如果C#/.NET Framework能够为程序员提供替代的内存管理解决方案,这将使他们能够克服GC的限制,它将受益。
- 程序员是一群非常聪明的人。GC技术使他们变得懒惰,但如果需要,他们将能够在适当的API下自行正确清理/释放内存。他们在GC技术之前就这样做了,现在他们正在使用其他不基于GC的语言来这样做。
粗略地说,替代方法可以分为两组:
- 一个堆解决方案——拥有某种托管堆增强解决方案
- 两种堆解决方案——拥有独立的托管堆和非托管堆
在1)的想法是拥有一个GC托管堆,它通过一些额外的API进行了增强,这将使开发人员能够直接传达不再需要某些对象/分配的内存,从而使释放更有效,并希望GC更快, 所以停顿会很少而且更短。下面讨论的GCD(*)是朝哪个方向的尝试。
在2)的想法是有两个堆,托管和非托管堆,程序员可以在垃圾收集堆或手动堆中分配对象之间进行选择。通常,该设计将允许对两个堆的引用。下面介绍的Snowflake项目(***)就是这样一种解决方案。
注:GCD被发现是未完成的研究最初,我为下面(*)列出的称为GCD的解决方案绘制了一个算法草图,并将其放在公众讨论中。在下面的评论中[24]用户“Davin On Life”在他的评论中表明,以它呈现的形式,并不像它看起来那么有效。因此,我将其作为未完成的研究撤回。
如果您对阅读“有问题的尝试”不感兴趣,请跳至(***)。
我决定保留提议的GCD解决方案的原始文本有两个原因。
- 最好记录下提出、辩论和发现不足的尝试和方法,以便我们不再讨论它们。而且,要记住它们为什么不足,这样我们就可以改进新的尝试。
- 虽然提出的GCD解决方案的第一次迭代可能会出现问题,但也许在接下来的迭代中,经过更多研究,我们将能够改进解决方案并克服问题。
在这里,我将提出一种替代的内存管理策略,在对这个主题进行短暂思考之后,我会想到它。同样,它是一个抽象概念,可以应用于任何语言,包括Java和.NET Framework。但由于我是一名软件工程师,最近主要在.NET Framework环境中工作,并且从那个环境中获得灵感,所以我将主要讨论如何在特定的C#语言环境中应用它。同样,这是应用于具体工程问题的推测性抽象思想阐述,我将其视为一种智力练习,并不意味着我对.NET框架的未来有任何权威。
所以,基本上,我建议在C#中添加除了GC之外的C++样式的删除和析构函数。让我们在进一步的文本中将其称为“带删除的垃圾收集”(GCD)解决方案。以下是建议的主要原则。
- 托管堆和GC在GCD框架中应用了它们的全部优势。对象在托管堆上用“new”分配。
- 感兴趣的类添加了C++风格的析构函数,假设类XYZ命名它为~~XYZ()。析构函数可以是虚拟的。
- C#语言通过“delete”运算符得到增强。如果应用于XYZ类的对象引用,它将调用虚拟析构函数~~XYZ()(如果存在)并从托管堆中释放对象。在这里,我的意思是暂时的同步调用,没有任何形式的“延迟评估”或“延迟执行”。
- 程序员可以随时在任何对象上自由调用delete操作符。如果对象有析构函数,则首先调用析构函数。如果从不调用某个对象的delete引用,则该对象将受到常规GC循环的影响。
- 最大的问题是“悬空引用”。如果有两个对object Obj1 的引用,并且在它的一个引用上被调用delete,那么另一个引用需要发生什么?我现在看到了两种方法:1)使用“智能指针”([17])等技术来不立即删除对象,或者2)删除对象并通过另一个引用报告空引用,我知道这可能导致“空引用异常”。我对此有疑问,并且对GC的内部结构了解得不够充分,无法知道它本身是否可以轻松支持方法1),这将是一个“更安全”的解决方案。
- 我不会在这里详细介绍析构函数的工作原理等,这是每个C++程序员都知道的。在析构函数内部,您可以自由删除属于原始对象分配的其他对象,或者您可以不关心并将它们留给GC来处理它们。
基本上就是这样。
GCD解决方案的好处以下是我认为GCD解决方案的好处。
- 首先,没有内存泄漏,与GC解决方案相同。如果他们关心,程序员可以自由地删除对象,但如果不关心,则释放由常规GC负责,因为所有对象都像以前一样位于托管堆上。
- 程序员有机会,但没有义务处理对象的释放。如果他们干预,对象将立即被释放,如果他们选择不干预,GC将处理对象。
- 程序员有机会注意到并处理关键分配。如果某个循环分配同一个对象1000次,那么一小行删除就可以解决问题,并且GC将减少1000个指针来分析,因此预计它的工作速度会快得多。如果程序员注意到不再需要一些大对象,那么几次删除将使GC的生活更轻松,因为GC仍然需要压缩堆。
- 如果某些对象创建了已分配包含对象的复杂图,这为GC创造了及时的工作,智能析构函数可以分解该对象并使GC从分析复杂图中解放出来,从而使其更快,并且GC暂停将有望更少和更短。
- 程序员没有义务编写“完整”的析构函数,他们可以拆解最重要的东西,比如最大的对象或最复杂的图形,然后交给GC来解决“小土豆”。
- 在删除/解除分配过程中有程序员的干预,GC需要分析的对象列表可以更短、更简单,从而使GC停顿很少且更短。
- 对于要求苛刻的高性能应用程序,程序员有机会几乎完全负责使用删除/析构函数释放对象,将GC仅作为备份策略,这将使GC循环和暂停不再需要且不存在。使用适当的API GC可以进入“do-not-work-until-emergency”状态,使GC暂停和延迟不存在。
- 在GCD解决方案中,保留了GC的所有好处,此外,如果程序员决定干预代码,则可以提高性能。
我在GCD内存管理框架中看到了三种主要的程序开发风格:
- 完全依赖GC。这与迄今为止所有程序员在Java或.NET Framework等环境中所做的相同。它可能是许多应用程序的适当策略。它非常适合初学者程序员。它非常适合原型制作。
- 关键对象的部分手动释放。程序员可能会决定干预他们注意到的热点,手动释放关键对象,如大对象,或大量分配小对象。这可以通过最少的工作对性能产生重大影响。他们可以决定不投入太多工作,将大部分工作留给GC。
- 完全手动控制对象的释放。在高性能应用程序、大型应用程序、复杂应用程序中,当有足够的合格劳动力可用时,程序员可能会决定完全或接近完全控制应用程序中的所有释放,以最大限度地提高性能。这可能是一个旅程,而不是一个大爆炸事件,因为如果他们不能一次解决所有问题,就不会受到惩罚,因为作为备份的GC总是在那里。
在这里,作为一个智力练习,我们将讨论从GC到GCD框架的过渡会是什么样子。为具体起见,我们将在.NET框架的示例中对其进行讨论。假设GCD被接受为内存管理策略。
- 首先,所有在GC框架下开发的程序都将继续在GCD框架下工作。所有库也将继续工作。因此,我们向后兼容现有的代码库或C#/.NET。
- 对于一个类XYZ,析构函数~~XYZ()看起来很像finalizes ~XYZ(),但性质不同。首先,析构函数必须是virtual。其次,终结器的任务是释放非托管资源,而析构器处理托管和非托管资源。通常,析构函数需要为适当的类调用终结器并删除它需要手动清理的显式托管资源(对象)。
- 关于C#中的IDisposable接口,在我看来,它确实是为了成为对象的析构函数。为了向后兼容,它可以保持原样,但可能会有一种模式如何使用指令/IDisposable接口可以替换为delete/destructor。
- 随着时间的推移,程序员可以使用GCD的新功能并将删除/析构函数应用于其应用程序的主体代码以提高性能。此外,随着时间的推移,C#/.NET库的发布者可以审查他们的库并通过一些手动释放调整来改进他们的代码。新版本的库只能在支持GCD内存管理的新.NET Framework中使用。
我认为需要一些工具来支持高效的GCD编程。至少,我希望自己看到的工具。
我记得我在C++环境中大量使用工具来定位内存泄漏和跟踪内存分配。那是Purify[5]和BoundChecker[6],它们具有一些“检测”代码的技术,并且可以生成一个非常好的内存泄漏列表和代码中完成分配的位置。几年前我使用了一些C#/.NET内存分析工具,但不熟悉最新版本。
我希望看到能够为GCD环境生成类似列表的工具。目的是支持程序员能够根据需要微调他们的应用程序关于内存分配/释放的问题。我想看到的是:
- 当然,托管堆上所有对象的列表,这些对象在代码中被分配和位置
- 而且,我还想查看所有被垃圾收集的对象的列表以及它们在代码中的分配位置。我想看到这样的报告:XVZ类的对象在第1234行被分配了1000次,并且被垃圾收集了1000次。这实际上是由GC处理的C++术语中的“内存泄漏”,并且是在GCD框架中手动释放的一个很好的候选,因此GC不需要处理它,这将释放GC额外的工作并使GC暂停更短。
因此,基本上,我想轻松了解GC工作,因此如果需要,我可以手动解析/解除分配对象,这样GC就不会努力工作并长时间阻塞/暂停应用程序。熟悉GC架构的人肯定能指出GC可以给程序员更多有用的信息,比如遍历哪些图需要很多时间,所以可以编写和应用一个聪明的析构函数。重点是优化程序员的工作,所以他们不会为所有类编写析构函数,而只为那些导致GC问题的类编写析构函数。我认为没有其他方法可以加快GC工作,除了让它做更少和更简单的工作。
Microsoft在.NET中试验非托管堆(***)一位匿名读者向我推荐了一些文章,这些文章描述了微软自己在.NET框架中引入非托管堆的实验,称为“雪花”项目([20], [21]. [22])。一组研究人员甚至从.NET代码创建了一个分支,并实施了一个解决方案并对其进行了测试。雪花计划是一项严肃的研究项目,涉及来自世界顶尖大学的3名研究人员和来自微软研究院的5名研究人员。我估计它可能包括十几名支持人员(IT、人力资源、项目管理等),持续了3个多月,预算很大。这意味着,如果你算上所有的工作时间,获得像[22]这样的研究论文可能要花费100万美元或更多。
这是该项目的概要。
- 作者一致认为“GC极大地提高了程序员的工作效率并确保了内存安全”。([22]),但是“……但是GC会带来性能成本……。对某些人来说可能是个问题。” ([21])
- 在他们的设计中,程序员可以选择在垃圾收集堆或手动堆中分配对象。
- 一个关键的设计目标是保持完整的GC互操作性,允许指向和来自两个堆的指针。
- 为了处理“悬空引用”的问题,他们开发了自己的技术/模式,称为“所有者和盾牌”(Snowflake API)。该技术/模式类似于危险指针[23]。
- 程序员如何知道应该在手动堆上分配哪些对象?该方法是使用堆分析工具来确定GC是否具有显着成本,然后识别存活并在老一代中收集的对象并寻找候选对象。
- 他们的.NET CoreCLR实现的实验结果显示“峰值工作集节省高达3倍,运行时提高2倍”([22])。这意味着某些应用程序将使用少3倍的内存,速度提高2倍。他们说性能优势是由于“这是可能的,因为对于非常大的对象池,GC会花费大量时间遍历对象图以释放内存。” ([21])。
- 该研究文章的日期为2017年,没有提及.NET产品中的潜在集成。
好吧,随着C#8和“可空引用类型”([18])的到来,它们现在已经成为标准,我对宣布过去几年我们所生活的非自然事物的勇气和决心感到惊讶。所有这些炒作都将数百万行代码从“string s=null”这样的表达式更改为“string? s=null”。我学会了用“void * p=0”这样的表达方式编程,所以真的没有看到“十亿美元的错误”[19]有什么问题。但是,无论破坏这么多现有代码行,为改变该范例所做的努力表明,对.NET Framework进行重大更改是可能的。如果当他们决定需要一个新的.NET内存管理策略时,他们表明他们可以推动这样的改变。
结论在本文中,我们首先分析了GC技术的现状及其带来的问题。然后我们讨论了它给.NET框架(意味着整个家庭的“.NET框架”、“.NET Core”、“.NET”和“Mono”)应用程序带来的问题,因为它是该框架中唯一可能的内存管理策略。
然后,我们讨论了另一种解决方案,即垃圾收集的使用与删除/析构函数的补充,这仍然是未完成的研究。
然后我们谈到了微软自己在该领域所做的一些研究,称为“雪花”项目。
我们认为,将GC作为唯一的内存管理策略是.NET框架的一个严重问题。一些替代方案和改进将是有益的,无论是类似于此处提出的GCD框架、微软“雪花”项目,还是一些完全不同的方法。时间会告诉我们.NET框架的发展方向。
参考- [1] Garbage Collector Basics and Performance Hints | Microsoft Docs
- [2] In managed code we trust, our recent battles with the .NET Garbage Collector
- [3] Roslyn code base - performance lessons (part 2) · Performance is a Feature!
- [4] Measuring the impact of the .NET Garbage Collector · Performance is a Feature!
- [5] IBM Rational Purify software is now available through the IBM Passport Advantage program
- [6] https://en.wikipedia.org/wiki/BoundsChecker
- [7] https://en.wikipedia.org/wiki/Graph_traversal
- [8] https://en.wikipedia.org/wiki/.NET_Framework
- [9] Large object heap (LOH) on Windows | Microsoft Docs
- [10] Fundamentals of garbage collection | Microsoft Docs
- [11] Garbage collector config settings - .NET | Microsoft Docs
- [12] Workstation vs. server garbage collection (GC) | Microsoft Docs
- [13] Background garbage collection | Microsoft Docs
- [14] Latency Modes | Microsoft Docs
- [15] https://en.wikipedia.org/wiki/Object_pool_pattern
- [16] Measuring the impact of the .NET Garbage Collector - An Update · Performance is a Feature!
- [17] https://en.wikipedia.org/wiki/Smart_pointer
- [18] Nullable reference types | Microsoft Docs
- [19] LinkedIn Login, Sign in | LinkedIn
- [20] https://www.microsoft.com/en-us/research/publication/project-snowflake-non-blocking-safe-manual-memory-management-net/
- [21] Microsoft Explores Manual Memory Management in .NET with Snowflake
- [22] https://www.microsoft.com/en-us/research/wp-content/uploads/2017/07/snowflake-extended.pdf
- [23] https://en.wikipedia.org/wiki/Hazard_pointer
- [24] Discussing Alternative Memory Management Strategy for .NET - CodeProject
https://www.codeproject.com/Articles/5329775/Discussing-Alternative-Memory-Management-Strategy