[翻译] 编写高性能 .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。如果你发现要复制缓冲区,可以尝试将其复制或合并到一个现有的缓冲区里,以避免任何新的内存分配。
[翻译] 编写高性能 .NET 代码--第二章 GC -- 避免使用终结器,避免大对象,避免复制缓冲区的更多相关文章
- [翻译] 编写高性能 .NET 代码--第二章 GC -- 减少分配率, 最重要的规则,缩短对象的生命周期,减少对象层次的深度,减少对象之间的引用,避免钉住对象(Pinning)
减少分配率 这个几乎不用解释,减少了内存的使用量,自然就减少GC回收时的压力,同时降低了内存碎片与CPU的使用量.你可以用一些方法来达到这一目的,但它可能会与其它设计相冲突. 你需要在设计对象时仔细检 ...
- [翻译] 编写高性能 .NET 代码--第二章 GC -- 将长生命周期对象和大对象池化
将长生命周期对象和大对象池化 请记住最开始说的原则:对象要么立即回收要么一直存在.它们要么在0代被回收,要么在2代里一直存在.有些对象本质是静态的,生命周期从它们被创建开始,到程序停止才会结束.其它对 ...
- [翻译] 编写高性能 .NET 代码--第二章 GC -- 减少大对象堆的碎片,在某些情况下强制执行完整GC,按需压缩大对象堆,在GC前收到消息通知,使用弱引用缓存对象
减少大对象堆的碎片 如果不能完全避免大对象堆的分配,则要尽量避免碎片化. 对于LOH不小心就会有无限增长,但LOH使用的空闲列表机制可以减轻增长的影响.利用这个空闲列表,我们可以在两块分配区域中间找到 ...
- [翻译] 编写高性能 .NET 代码--第二章 GC -- 配置选项
配置选项 在基于"less rope to hang yourself with"思想下,.NET 框架没有给开发提供很多太多的配置选项.但在大多数情况下,GC会跟你的硬件配置,及 ...
- [翻译]编写高性能 .NET 代码 第二章:垃圾回收
返回目录 第二章:垃圾回收 垃圾回收是你开发工作中要了解的最重要的事情.它是造成性能问题里最显著的原因,但只要你保持持续的关注(代码审查,监控数据)就可以很快修复这些问题.我这里说的"显著的 ...
- [翻译]编写高性能 .NET 代码 第二章:垃圾回收 基本操作
返回目录 基本操作 垃圾回收的算法细节还在不断完善中,性能还会有进一步的提升.下文介绍的内容在不同的.NET版本里会略有不同,但大方向是不会有变动的. 在.net进程里会管理2个类型的内存堆:托管和非 ...
- [翻译]编写高性能 .NET 代码 第一章:性能测试与工具 -- 平均值 vs 百分比
<<返回目录 平均值 vs 百分比 在考虑要性能测试的目标值时,我们需要考虑用什么统计口径.大多数人都会首选平均值,但在大多数情况下,这个正确的,但你也应该适当的考虑百分数.但你有可用性的 ...
- [翻译]编写高性能 .NET 代码 第一章:工具介绍 -- Visual Studio
<<返回目录 Visual Studio vs虽然不是全宇宙唯一的IDE,但它是.net开发人员最常用的开发工具.它自带一个性能分析工具,你可以使用它来做开发,不同的vs版本在工具上会略有 ...
- [翻译]编写高性能 .NET 代码 第一章:工具介绍 -- Performance Counters(性能计数器)
<<返回目录 Performance Counters(性能计数器) 性能计数器是监视应用程序和系统性能的最简单的方法之一.它有几十个类别数百个计数器在,包括一些.net特有的计数器.要访 ...
随机推荐
- Struts2中Action接收参数的方法主要有以下三种:
Struts2中Action接收参数的方法主要有以下三种: 1.使用Action的属性接收参数(最原始的方式): a.定义:在Action类中定义属性,创建get和set方法: b.接 ...
- [知了堂学习笔记]_css3特效第一篇--旋转的背景&翻书效果
一.html遮盖层与css3的旋转动画 >效果图(加载可能会慢一点儿,请稍等...): >实现思路:在一个大的div中装入一个底层img和顶层的div(里面的内容按照以上图片呈现的样式布局 ...
- oracle02
SQL语句完整结构: select from where group by having order by 今天分享的知识点:(1)分组查询 select 中非组函数的列需要在group by 进行参 ...
- vue 的准备项目架构环境配置
一.环境搭建 中国镜像 composer config repo.packagist composer https://packagist.phpcomposer.com 命令 composer in ...
- 转-WebService到底是什么?
原文链接:WebService到底是什么? 一.序言 大家或多或少都听过WebService(Web服务),有一段时间很多计算机期刊.书籍和网站都大肆的提及和宣传WebService技术,其中不乏很多 ...
- text和submit框的border问题
A1:在input框中,为type为text的输入框增加边框,它会在内容区域外额外增添,但是在submit框中,它会占用内容区块的一部分作为边框 <style type="text/c ...
- ng机器学习视频笔记(一)——线性回归、代价函数、梯度下降基础
ng机器学习视频笔记(一) --线性回归.代价函数.梯度下降基础 (转载请附上本文链接--linhxx) 一.线性回归 线性回归是监督学习中的重要算法,其主要目的在于用一个函数表示一组数据,其中横轴是 ...
- 深度优化LNMP之MySQL
MySQL数据库优化框架体系 1.硬件层面优化 2.操作系统层面优化 3.MySQL数据库层面优化 4.MySQL安全优化 5.网站集群架构上的优化 6.MySQL流程.制度控制优化 1 硬件层面优化 ...
- java基础(六) switch语句的深入解析
引言 switch 语句是非常的基础的知识,掌握起来也不难掌握,语法比较简单.但大部分人基本是知其然,不知其所以然.譬如 早期JDK只允许switch的表达式的值 int及int类型以下的基本类型 ...
- spring之p命名空间注入
<bean id="personId" class="com.itheima.f_xml.c_p.Person" p:pname="禹太璞&qu ...