博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
通过减少内存使用改善.NET性能
阅读量:6594 次
发布时间:2019-06-24

本文共 1792 字,大约阅读时间需要 5 分钟。

对.NET的性能调优来说,我们有一个普遍被误解的观念:规避内存分配的重要性。人们认为,由于内存分配是快速的,因此很少会对性能产生影响。

\\

要理解导致这种误解的原因,我们必须回到在C++和Visual Basic 4到6中所看到的COM编程时代。对于COM,内存是使用引用计数形式的垃圾回收器进行管理的。每当将一个对象分配给一个引用变量时,就会增加一个隐藏的计数器。如果变量被重新分配或从作用域退出,计数器就会被取消。如果计数器达到0,对象就会被删除,将内存释放到其他地方。

\\

这种内存管理系统是“确定的”。通过仔细分析,你可以确定何时删除一个对象。这意味着你可以自动释放数据库连接等资源。而对于.NET而言,你需要一个单独的机制(例如,销毁/启用)以确保非内存资源能够及时地被释放。

\\

引用计数垃圾收集器有三个主要的缺点。首先,它们容易受到“循环引用”的影响。如果两个对象相互引用,即使是间接的,那么引用计数也不可能降为0,这便会导致内存泄漏的发生。我们必须小心地编写代码,要么避免循环引用,要么提供某种解构方法以便在当对象不再需要时中断循环。

\\

工作在多线程环境中时会遇到另一个主要的缺点。为了避免竞态条件,某种类型的锁机制(例如:锁住、增量、旋锁等)需要确保重新计数仍然是正确的。这些操作出奇的昂贵。

\\

最后,可用内存位置的列表可能会变成碎片化的,在活动对象之间会产生许多小的、不可用的空间。内存分配通常涉及到遍历一个有空闲空间的连续链表,以便寻找到一个足够大的位置来满足需求对象。(内存碎片在.NET中也存在于“大对象堆”或“LOH”。)

\\

相比之下,像.NET或Java那样将内存分配到一个“标记-清扫”形式的垃圾回收器中,便是一个简单的指针增量机制。赋值并不比分配一个整数更昂贵。只有当GC实际运行时,才会支付实际成本,而且通常通过使用分代收集器来缓解这种情况。

\\

当.NET刚出现的时候,许多人抱怨.NET的垃圾回收器不确定性的表现将会损害性能并且难以解释。当时微软的反驳是,对于大多数用例来说,尽管间歇的GC会暂停,但“标记-清扫”的垃圾回收器实际上会更快。

\\

不幸的是,随着时间的推移,这条信息变得有些混乱。即使我们接受这样一种理论,即“标记-清扫”的垃圾回收器速度比引用计数更快,但这并不意味着它在绝对意义上是必须的。内存分配和相关的内存压力通常是很难检测性能问题的原因。

\\

而且,使用的内存越多,CPU缓存的效率就越低。虽然主RAM很大,以至于在大多数用例中几乎不会使用到基于磁盘的虚拟内存,但是相比之下,CPU中的缓存是很小的。从RAM中填充CPU缓存所需的时间可能会占用数十甚至数百个CPU周期。

\\

在最近的一篇文章中,Frans Bouma确定了几种。虽然他着重关注改善ORM性能,但这些建议在各种情况下都很有用。他的这些建议包括:

\\

避免参数数组

\\

参数关键字是有用处的,但与普通的函数调用相比要昂贵,因为它需要内存分配。API应该为常用的参数计算提供无参数重载。

\\

还应该提供一个IEnumerable\u0026lt;T\u0026gt; 或者IList\u0026lt;T\u0026gt;的重载,这样集合在调用函数之前就不需要多此一举的被复制到一个数组中了。

\\

如果定义之后立即添加数据,可先预定义数据结构的大小

\\

List\u0026lt;T\u0026gt;或其他集合类可以在被填充时多次调整大小。每次调整大小的操作都会分配另一个内部数组,并由前一个数组填充。你可以通过为集合的构造函数提供一个容量参数来避免这种开销。

\\

惰性的初始化成员

\\

如果你知道一个给定对象在大多数情况下是不需要的,那么你应该使用延迟初始化来避免过早地分配内存给它。通常这是手动完成的,因为Lazy\u0026lt;T\u0026gt; 类本身需要分配内存。

\\

早在2011年,我们就曾报道过。他们的报告显示,在创建一个\u0026lt;int32\u0026gt;任务的时候花费的时间减少了49%到55%,所需空间大小减少了52%。

\\

查看英文原文

\\

感谢对本文的审校。

\

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至。也欢迎大家通过新浪微博(,),微信(微信号:)关注我们。

转载地址:http://jecio.baihongyu.com/

你可能感兴趣的文章
LVS+Keepalived实现高可用集群
查看>>
我的友情链接
查看>>
unbantu安装 mysql --- 百度云
查看>>
sql2008性能计数器注册表配置单元一致性失败
查看>>
LNMP环境搭建
查看>>
我的友情链接
查看>>
学习linux—— 磁盘相关指令
查看>>
词法分析与语法分析简介
查看>>
JS中的默认行为
查看>>
我的友情链接
查看>>
Checkio代码闯关小计
查看>>
从oracle到mysql,主从到分库,一个普通项目数据库架构的变迁
查看>>
从零开始学wordpress 之四
查看>>
[LeetCode] Course Schedule
查看>>
selenium层级定位及鼠标键盘操作
查看>>
SpringBoot跨域问题解决方案
查看>>
(转载)hibernate3.0配置文件模板
查看>>
46、练习:输出指定目录下的所有文件名称
查看>>
IP地址与数字地址相互转换
查看>>
Knockout.Js官网学习(创建自定义绑定)
查看>>