[翻译] 编写高性能 .NET 代码--第二章 GC -

发布时间:2017-7-1 11:53:07编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"[翻译] 编写高性能 .NET 代码--第二章 GC -",主要涉及到[翻译] 编写高性能 .NET 代码--第二章 GC -方面的内容,对于[翻译] 编写高性能 .NET 代码--第二章 GC -感兴趣的同学可以参考一下。

[翻译] 编写高性能 .NET 代码--第二章 GC -- 避免使用终结器,避免大对象,避免复制缓冲区

避免使用终结器

如果没有必要,是不需要实现一个终结器(Finalizer)。终结器的代码主要是让GC回收非托管资源用。它会在GC完成标记对象为可回收后,放入一个终结器队列里,在由另外一个线程执行队列里对象的终结器方法。这就意味着,如果你实现一个类的终结器,你必须保证在它在终结器执行后能被正常回收。这需要消耗一些CPU资源在清理对象上,会极大降低GC的整体效率。
如果你实现一个终结器,你也必须实现一个IDisposable接口用来清理资源,并在Dispose方法里调用GC.SupperessFinalize(this)将对象从终结器队列里移除。如果你在下次回收之前,正确的调用了Disspose方法,就不会让终结器执行。下面的栗子就是正确的演示了这个模式。

    class Foo : IDisposable    {        ~Foo()        {            Dispose(false);        }        public void Dispose()        {            Dispose(true);            GC.SuppressFinalize(this);        }        protected virtual void Dispose(bool disposing)        {            if (disposing)            {                this.managedResource.Dispose();            }            // Cleanup unmanaged resourced            UnsafeClose(this.handle);            // If the base class is IDisposable object             // make sure you call:            //base.Dispose(disposing);        }    }

你可以通过 [http://www.writinghighperf.net/go/15] 获得过的关于Dispose模式与终结器的更多信息。

注意 有些人认为终结器一定会被执行。正常情况下没错,但这不是绝对的。如果一个程序被强制终止,那么进程会立即消失,终结器自然也不会执行。当然主动退出时也许会有一个短暂的等待进程关闭时间,但如果你的终结器在终结器列表的后面,也是有可能不会被执行。此外由于终结器队列是循序执行,如果某个终结器进入了死循环,那么后面的终结器就不会被执行到。终结器不是执行在GC线程里,但他们会引发GC。

避免大对象

在分析了大量的程序代码后,大对象的边界被定义在85000 bytes上。任何大于等于这个边界值的对象都会判定为“大对象”,需要分配在一个单独的堆里。
我们希望尽可能的避免在大对象堆上进行分配。这不仅会导致更长的GC,也更容易造成内存碎片,让内存的分配边界随着时间不对增加。
为了避免这些问题,你需要严格控制程序在大对象堆里分配内容。你需要统筹安排你的对象在应用程序生存周期里的分配方案。
LOH是不会自动压缩的,但在.NET 4.5.1 之后,你还是可以通过特定方法去通知GC进行压缩。然而,这个是你最后的手段,因为这将导致一次很长的暂停。在做这之前,你还是好好想想,应该如何避免进入这个情况。

避免复制缓冲区

如果可能,你应该尽量避免复制数据。例如:如果你打算将一个文件数据读入MemoryStream(如果你需要一个大的缓冲区,最好做一个合并)。一旦分配了内存,每个组件都将从这个数据里的同一个副本里读取数据,并将其视为开发准则。

如果你只需要使用这个缓冲区里的一部分,可以使用ArraySegment类来访问这个缓冲区的部分数据。你可以使用 ArraySegment的Api来访问原始数据,你可以将它附加到一个创建的MemoryStram里。你所做的这一切不会产生新的数据副本。

var memoryStream = new MemoryStream();var segment = new ArraySegment<byte>(memoryStream.GetBuffer(), 100, 1024);var blockStream = new MemoryStream(segment.Array, segment.Offset, segment.Count);

复制内存最大的问题不在CPU而是GC。如果你发现要复制缓冲区,可以尝试将其复制或合并到一个现有的缓冲区里,以避免任何新的内存分配。

下一篇:第二章 GC -- 将长生命周期对象和大对象池化


上一篇:Spring中的类型转换与数据绑定(PropertyEditor、ConversionService、Data Binding、Formatter)
下一篇:css权重

相关文章

相关评论

本站评论功能暂时取消,后续此功能例行通知。

一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!

二、互相尊重,对自己的言论和行为负责。

好贷网好贷款