首页 > 图书中心 >图书详情
.NET内存管理宝典
作者:[波兰] 康拉德·科克萨(Konrad Kokosa)著 叶伟民 涂曙光译
定价:139元
印次:1-1
ISBN:9787302571339
出版日期:2021.03.01
印刷日期:2021.03.03
了解.NET内存管理的内部工作原理、陷阱和技术,以便有效地避免软件中出现各种性能和可伸缩性问题。尽管.NET具有自动内存管理功能,但了解 .NET的内存管理工作原理以及如何最好地编写与之高效交互的软件方面仍有许多益处。《.NET内存管理宝典 提高代码质量、性能和可扩展性》是你通过了解和处理 .NET 中的内存管理来编写出更好软件的全面指南。 《.NET内存管理宝典 提高代码质量、性能和可扩展性》经过了 Microsoft 的 .NET 团队全面审查,包含 了25 个有价值的故障排除方案,旨在帮助诊断具有挑战性的内存问题。读者还将受益于多个 .NET 内存管理”规则”,这些规则介绍了编写内存感知代码的方法以及避免常见的破坏性陷阱的方法。 本书内容 ● 了解自动内存管理的理论基础 ● 深入研究.NET内存管理的各个方面,包括对垃圾回收(GC)实现的详细介绍,这些知识如果自行摸索需要多年经验才能获得 ● 获得如何将这些知识应用于实际软件开发中的实用建议 ● 使用与 .NET 内存管理相关工具的实用知识来诊断各种与内存相关的问题 ● 探索高级内存管理的各个方面,包括使用Span和Memory类型
more >前 言 在计算机科学的历史中,内存一直存在——从穿孔卡片到磁带,再到如今复杂的DRAM芯片。它也将会永远存在,可能会以科幻全息芯片的形式出现,或者甚至是我们现在无法想象的更神奇的事物。当然,内存的存在并非没有原因。众所周知,计算机程序被认为是结合在一起的算法和数据结构。我非常喜欢这句话。大概多数人都听说过Niklaus Wirth撰写的Algorithms+Data Structures=Programs一书,正是在这本书中创造了这个伟大的句子。 在软件工程领域的最早时期,内存管理就以其重要性而闻名。从第一台计算机开始,工程师就必须考虑算法(程序代码)和数据结构(程序数据)的存储。如何加载和存储以及在何处加载和存储这些数据以供以后使用一直都很重要。 在这方面,软件工程和内存管理总是天生相关的,就像软件工程和算法一样。我相信它将永远都是这样。内存是一种有限的资源,而且将永远都是。因此,在某些时候或某种程度上,内存将永远留在未来的开发人员的脑海中。如果一种资源是有限的,那么总会有某种错误或滥用导致该资源的匮乏。内存也不例外。 话虽如此,关于内存管理,有一件事是肯定不断变化的——就是内存的大小。最早期的开发人员都清楚地知道他们程序里内存的每一位(bit),那时他们只有几千字节(KB)的内存。每十年这个数字都在增长,今天,内存的单位为吉字节(GB),而太字节(TB)和拍字节(PB)则在敲门。随着内存大小的增加,访问数据的时间将会减少,从而有可能在令人满意的时间内处理完所有这些数据。但是,即使我们可以说内存处理是很快的,使用简单的内存管理算法来尝试处理所有GB量级的数据而不进行任何优化和更复杂的调整也是不可行的。这主要是因为内存访问时间的增长速度比使用它们的CPU的处理能力要慢。因此必须格外小心,以免造成内存访问瓶颈,从而限制CPU的能力。 这使得内存管理不仅至关重要,而且是计算机科学中非常有趣的一部分。自动的内存管理虽然能够使其变得更好,但这并不像“释放未使用的对象”这么简单的一句话那么容易。所要管理的内容、如何以及何时进行内存管理这些简单方面都使其成为持续不断的改进旧算法和发明新算法的过程。无数的科学论文和博士学位论文正在考虑如何以最佳方式来自动地管理内存。诸如国际内存管理专题研讨会(ISMM)的活动每年都会展示在该领域做了多少工作,比如在垃圾回收、动态分配以及与运行时、编译器和操作系统的交互等方面。然后,这些学术研讨会转变为我们在日常工作中使用的商业化和开源产品。 .NET是托管环境的一个完美示例,在该环境中,所有这些复杂性都被隐藏在底层,开发人员可以将其作为一个令人愉快的、随时可用的平台使用。确实,我们可以在不用了解这些底层复杂性的情况下使用它,这是.NET的一项伟大成就。然而,我们的程序对性能敏感度方面的需求越强,就越不可能避免要获得关于底层工作方式和原因的任何知识。而且,在我看来,了解我们每天使用的东西是多么有趣啊! 我写《.NET内存管理宝典》的方式是很多年前当我开始进入.NET性能和诊断领域时我喜欢阅读文献资料的一种方式。因此,《.NET内存管理宝典》并非从传统的有关每代堆(Heap)和堆栈(Stack)的介绍或说明开始。相反,我会从内存管理的基础知识和原理开始。换言之,我会试着用一种能让你感觉到这是一个非常有趣的话题的方式来写《.NET内存管理宝典》,而不仅是展示了“这里有一个.NET垃圾回收器,它能做这做那”。我不但提供了这些知识的内容,而且提供这些知识的工作方式,更重要的是讲解.NET内存管理的幕后原理。因此,你以后读到的关于这个话题的所有内容都应该能够更容易地理解。我会试图用不仅仅是与.NET相关的通用性知识来启发你,尤其是在前两章。这将带来对该主题的更深入理解,这通常也适用于其他软件工程任务(即基于对算法、数据结构和其他优秀工程技术的理解)。 我想以一种让每个.NET开发人员都满意的方式来编写《.NET内存管理宝典》。无论你有没有编程经验,都应该能在《.NET内存管理宝典》中找到一些有趣的知识。当我们从基础开始时,初级程序员很快就会有机会深入了解.NET内部。更高级的程序员会发现许多更有趣的实现细节。最重要的是,无论经验多少,每个人都能够从所提供的实用示例代码和问题诊断中受益。 因此,从《.NET内存管理宝典》中获得的知识应该能够帮助你编写更好的代码 ——更好地了解性能和内存,并充分利用相关功能,而不必先读完所有内容。这些知识还可以提高应用程序的性能和可扩展性——代码要面向的内存越多,则对资源瓶颈的暴露和资源利用率就越少。 我希望所有这些能使这本书比简单描述.NET框架及其内部状态更全面和持久。不管未来.NET框架会如何发展,我相信《.NET内存管理宝典》中的大部分知识在很长一段时间内都是正确的。即使某些实施细节会发生变化,由于《.NET内存管理宝典》的知识,你也应该能够很容易地理解它们,因为基本原则不会变化得这么快。祝你在自动内存管理这个庞大而有趣的主题中度过一段愉快的时光! 说到这里,我还想强调《.NET内存管理宝典》中没有特别提到的内容。内存管理的主题,尽管乍一看似乎非常专业且狭窄,但其实却出人意料地广泛。虽然我涉及了很多主题,但由于篇幅所限,有时无法按我希望的方式详细介绍它们。这些省略掉的主题包括对其他托管环境(如 Java、Python或Ruby)的全面参考。我也要向F#粉丝道歉,因为很少提到这种语言。因为没有足够的页面来简单地进行过硬的描述,我不想发布任何不全面的内容。我本来想对Linux环境给予更多的关注,但是这个工具主题太新了,在编写《.NET内存管理宝典》时,我只在第3章给你一些建议(出于同样的原因也完全省略了macOS世界)。显然,类似的,我还省略了大部分其他与内存无关的性能部分,如多线程主题。 其次,尽管我已经尽了最大努力来介绍所讨论的主题和技术的实际应用,但是不可能做到覆盖所有方面和尽善尽美。实际应用实在是太多了。我更希望读者能全面阅读,并结合日常工作来重新思考主题并运用起来,从而掌握该知识。当了解到某事物的工作原理后,你将能够使用它!这尤其包括书中场景。请注意,《.NET内存管理宝典》中包含的所有场景都是出于演示目的。它们的代码被精简到最低限度,以便更容易地展示出单个问题的根本原因。被观察到的不当行为背后可能有多种原因(例如,许多方法可能会发现有托管内存泄漏)。使用场景这种编写方式有助于用单个示例原因来说明此类问题,因为很显然不可能在一本书中包含所有可能的原因。此外,在真实场景中,你的调查将充斥着大量嘈杂的数据和虚假的调查路径。通常没有单一的方法能解决所描述的问题,但是有许多方法可以在问题分析期间找到根本原因。这使得这种故障排除是纯粹的工程任务与一点点由你的直觉支撑的艺术的混合体。另外请注意,场景有时是会相互引用的,以免重复相同的步骤、图形和描述。 在这本书中,我专门避免提及各种特定技术的案例和问题的来源。这会包含太多的技术细节。如果我是在10年前写这本书,我可能不得不列出ASP.NET WebForms 和 WinForms 中内存泄漏的各种典型场景。如果是在几年前写,则要列出ASP.NET MVC、WPF、WCF、WF……如果现在写,就要列出ASP.NET Core、EF Core、Azure Functions等。说到这里,我希望你能够明白我所说的意思。这样的知识很快就会过时。这本书如果充满了WCF内存泄漏的例子,那么今天将几乎没有人会感兴趣。我的一个超级粉丝说:“授人以鱼,你养活他一天;授人以渔,你将养活他一辈子”。因此,《.NET内存管理宝典》中的所有知识、所有场景,都在教你如何捕鱼。如果你拥有了足够的知识和理解,那么所有问题,无论潜在的特定技术如何,都可以同样的方式得到诊断和解决。 所有这一切也使得阅读这本书相当困难,因为有时书中充满了细节,也许还有海量的信息。无论如何,我鼓励你深入而缓慢地阅读,抵制只是略微一读的诱惑。例如,要想充分利用《.NET内存管理宝典》,应该仔细研究展示和呈现的代码(而不仅仅是看它们一眼而已,这些代码是很常见的,因此它们很容易被忽略)。 我们生活在一个好时代,因为CoreCLR 运行时开源了。这使得对CLR 运行时的理解能力更上一层楼。不需要猜测,也没有奥秘,一切都在代码中,都可以读取和理解。因此,我的研究主要是基于CoreCLR的GC代码(该部分代码和 .NET Framework的GC代码是相同的)。我花了无数个日夜来分析这些大量的出色的工程工作。我认为它们棒极了,我相信有些人也会喜欢研究著名的gc.cpp文件,它有好几万行代码。然而,它的学习曲线非常陡峭。为了帮助你实现这一点,我经常会留下一些线索,对所描述的主题会说明可以在CoreCLR的何处代码中进行研究。我建议请随时从gc.cpp文件获得更深刻的理解。 阅读完《.NET内存管理宝典》后,你应该能够: ● 在.NET中编写有性能和内存意识的代码。尽管所提供的示例是用C#编写的,但是我相信你在此获得的理解和工具箱,也同样可以应用于F#或VB.NET。 ● 诊断与.NET内存管理有关的典型问题。由于大多数技术都基于ETW/LLTng数据和SOS扩展,因此它们在Windows和Linux上都适用(Windows上的工具会更高级)。 ● 理解CLR在内存管理领域的工作原理。我花了很多精力来解释它的运作方式和原因。 ● 充分理解GitHub上许多有趣的C#和CLR运行时问题,甚至能以你自己的想法参与其中。 ● 阅读CoreCLR(特别是gc.cpp)文件中的GC代码,并充分理解,以便进行进一步的调查和研究。 ● 充分了解有关Java、Python或Go等不同环境中GC和内存管理的信息。 《.NET内存管理宝典》的内容大概如下。 第1章是对内存管理的非常笼统的理论介绍,几乎没有提到.NET。第2章同样是硬件和操作系统级别的内存管理的通用性介绍。这两章都可以作为一个重要的、但可选的介绍。它们对该主题进行了有益的、更广泛的研究,对《.NET内存管理宝典》的其余部分很有用。虽然我强烈建议你阅读它们,但如果你急于学习最实用的与.NET相关的主题,则可以忽略它们。给高级读者的一个提示——即使你认为前两章的主题对你来说过于浅显,也请阅读它们。我已尝试把那些你可能感兴趣的信息包括进去。 第 3 章专门介绍测量和各种工具(其中的某些工具在《.NET内存管理宝典》后面会经常用到)。这一章主要包含了一个工具列表以及如何使用这些工具。如果你主要对《.NET内存管理宝典》的理论部分感兴趣,你可以只略读这一章。另一方面,如果你打算在诊断问题时大量使用《.NET内存管理宝典》的知识,你可能会经常回顾这一章。 第4章是我们开始深入讨论.NET的第1章,同时仍然依旧以一种通用的方式让我们理解一些相关的内部结构,如.NET类型系统(包括值类型与引用类型)、字符串内联或静态数据。如果你真的很着急,不妨从这一章开始阅读。第5章介绍了第一个真正的内存相关主题——.NET应用程序中的内存组织方式,介绍了小对象堆(Small Object Heap,SOH)和大对象堆(Large Object Heap,LOH)的概念以及段(Segment)的概念。第6章进一步探讨与内存相关的内部结构,这些内部结构专门用于分配内存。出乎一些人意料的是,用了相当大篇幅的一章来专门针对这一理论上简单的主题。该章占用了相当的篇幅来讲述一个重要的部分:对各种分配来源的描述,从而避免这些情况的出现。 第7~10章是描述GC如何在.NET中工作的核心部分,并附有结合这些知识的实际示例和注意事项。为了不让读者因同时接收了太多信息而不知所措,这些章节介绍了GC最简单的方式——非并发工作站。另一方面,第11章专门介绍了所有其他方式,并综合考虑了可供选择的各种方式。第12章总结了《.NET内存管理宝典》的GC部分,描述了三种重要的机制:终结(Finalization)、Disposable对象和弱引用。 最后三章构成了《.NET内存管理宝典》的“高级”部分,解释.NET内存管理核心部分之外的工作原理。例如,第13章介绍了托管指针的主题,并更深入探讨结构(包括最近添加的ref结构)。第14章对最近越来越流行的类型和技术给予了越来越多的关注,比如Span<T>和Memory<T>类型。还有一节专门讨论面向数据设计这一鲜为人知的主题,以及关于最近的C#特性(比如可以为空的引用类型和管道)等做了简单介绍。第15章,也就是最后一章,描述了如何从代码中控制和监视GC,包括GC类API、CLR Hosting或ClrMD库。 《.NET内存管理宝典》的大部分源代码清单可在配套的GitHub代码库https://github.com/Apress/pro-.net-memory找到,也可扫描封底二维码下载。它们按章节组织,并且其中大多数包含了两个解决方案:一个用于执行基准,另一个用于其他代码清单。请注意,虽然所包含的项目包含了《.NET内存管理宝典》的代码清单,但通常会有更多的代码供你查看。如果你想使用或试验一个特定的代码清单,最简单的方法就是搜索它的编号,并对它和它的用法进行试用。但我也鼓励你在项目中寻找特定的主题,以便更好地理解。 在此我想提及一下一些重要的约定。最相关的一个是区分以下两个贯穿了《.NET内存管理宝典》的主要概念: ● 垃圾回收——回收不再需要的内存的过程(即大家通常所理解的)。 ● 垃圾回收器——实现垃圾回收的特定机制,最明显的是在.NET GC的上下文中。 《.NET内存管理宝典》自成一体,没有涉及许多其他材料或书籍。显然,我需要参考各种资源来获取很多伟大的知识来完成《.NET内存管理宝典》。下面列出了我选择的、作为补充知识来源的建议书籍和文章。 ● Pro .NET Performance,Sasha Goldshtein, Dima Zurbalev, Ido Flatow著(Apress, 2012) ● CLR via C#, Jeffrey Richter著(Microsoft Press, 2012) ● Writing High-Performance .NET Code, Ben Watson著(Ben Watson, 2014) ● Advanced .NET Debugging, Mario Hewardt著(Addison-Wesley Professional, 2009) ● .NET IL Assembler, Serge Lidin著(Microsoft Press, 2012) ● Shared Source CLI Essentials, David Stutz著(O’Reilly Media, 2003) ● “Book of The Runtime”运行时开发团队自己编写的开源文档,可通过https://github.com/ dotnet/coreclr/blob/master/Documentation/botr/README.md访问。 此外,还有大量的知识散落在各种在线博客和文章中。但是,与其用这些页面列表来充斥《.NET内存管理宝典》版面,不如将你重定向到由Adam Sitnik维护的一个伟大的代码库https://github.com/adamsitnik/awesome- dot-net-performance。
more >