[翻译] 编写高性能 .NET 代码--第二章 GC -- 配置选项
配置选项
在基于“less rope to hang yourself with”思想下,.NET 框架没有给开发提供很多太多的配置选项。但在大多数情况下,GC会跟你的硬件配置,及可用资源以及程序自己的行为做调整。当然也提供一些高级的配置使用,但这取决于你程序的类型。
工作站与服务器
你首要的是为应用选择是在工作站还是服务器模式下运行。
系统默认为工作站模式。在这种模式下,GC在触发回收时,回收线程与当前主线程的优先级一样。对于简单的应用程序,特别是存在工作站里有多个托管进程需要做交互的情况下,以及单处理器的计算机上,这可能是唯一的选择,你试图修改任何配置对运行不会产生任何影响。
服务器模式则会给每个业务逻辑进程创建一个专用的线程。这个线程会运行在高优先级(THREAD_PRIORITY_HIGHEST),但平时这个线程会处于休眠状态,一旦需要做GC就会被唤醒。完成GC后又会进入休眠。
此外,CLR还会为每个处理器分配一个单独的堆。每个处理器堆里,包含一个小对象堆和大对象堆。从你的应用程序角度上看,你的代码不知道引用的对象是属于哪个堆上面的(他们都有相同的虚拟地址空间)。
使用多个堆有下一些优点
- 垃圾回收可以并行处理。每个GC线程处理一个对应的堆。这是的服务器模式的GC比工作站模式要快的原因。
- 某些情况下,分配速度会更快,尤其是将大对象相对分配在同一个堆上快。还有一些其他内部差异,比如内存段的大小,越大的段在做垃圾回收时时间也会越长。
你可以在App.config 文件里的节点里配置。
<configuration>
<runtime>
<gcServer enabled="true"/>
</runtime>
</configuration>
你要如何选择工作站或者服务器模式吗?
如果一个多处理器机器上只运行你的应用程序,那么最明智的选择是:服务器模式。它在大多数情况下可以降低GC的延迟。
另一位方面,如果你的机器有多个托管进程的应用程序,则需要具体分析了。如果这几个托管应用都采用服务器模式,那么会创建很多个高优先级的线程,这个会对线程调度产生冲突和影响。在这种情况下,最好使用工作站模式。
如果你真的想在同一个台机器里的多个应用程序开启服务器GC模式,还有另外一种选择,就是为应用程序绑定特定的CPU。
无论你选择哪种模式,本书的大部分技巧都使用这两种模式。
后台GC
修改后台GC配置会更改2代对象的回收策略。相对于0代和1代的回收的前台GC,它不会中断当前应用里其他的线程执行。
后台GC在会而外创建一个线程用来处理2代对象的回收。这意味着,如果你同时开启后台GC和服务器GC,你将为每个处理器创建2个线程来处理GC。但这没啥大不了的,虽然进程里多了很多个线程,但这些线程在大部分时间里还是不工作的。
在你的应用执行的时候GC也可以同时进行,但在某些情况下,还是会发生阻塞。在这时,后台GC还是会将应用程序里的其它线程给挂起。
如果使用工作站模式,则始终开启后台GC模式,从.NET4.5开始,默认情况下服务器GC模式下也会开启,当然你也可以关闭它。
以下是关闭后台GC的配置
<configuration>
<runtime>
<gcConcurrent enabled="false"/>
</runtime>
</configuration>
实际上,我们很少有理由去禁用后台GC。如果你想通过禁用后台GC的线程来提高你的应用程序在CPU的占用率,但这个想法是不现实的。但如果是减少GC的延迟或者频率可以考虑关闭它。
低延迟模式
如果你的应用希望在一段特定时间里高速执行,不希望被GC的2代回收打扰。你可以通过改变 GCSettings.LatencyMode 的设置来实现。
LowLatency—只能在工作站模式运行,它可以暂停2代回收。
SustainedLowLatency—可以在工作站和服务器模式下执行。它可以暂停完整的2代回收,但如果你开启里后台GC模式,你还是可以在后台GC线程里对2代对象做回收。
这两种模式都将大大的增加内存的消耗,因为它没对内存做压缩。如果你的应用需要消耗大量的内存,则最好避免开启这两个模式。
当你要准备进入低延迟模式前,最好手动执行一次完整的GC(GC.Collect(2, GCCollectionMode.Forced)。等离开低延迟模式后,也手动触发一次完成GC。
默认情况下,是不需要开启这个模式。只有你的程序执行时间不要被GC打扰才需要开启,不用在全过程都开启。举个栗子:如果你有一个股票交易的高频应用,在交易时间段里不希望发生GC回收暂停应用执行。但在股市交易结束后,你可以关闭这个模式进行完整的GC回收直到股市重新开市。
如果要开启低延迟模式,至少要符合以下标准:
- 在正常执行期间,完整的垃圾回收操作是不可接受的
- 应用程序消耗的内存要远小于可分配内存
- 应用程序在开启低延迟模式后,要有足够的内存撑到下一次手动执行完整回收或者重启。
这是一个很少用的配置,如果你要使用请三思而后行,因为开启之后会出现一些意想不到的后果。如果你认为还是有必要使用,请确保你的应用经过了充分测试。在开启后,系统会产生更频繁的0代和1代的回收操作,用来减少完整的回收,这可能会导致一些其他性能问题。这可能会导致解决了一个又另外产生了一个问题。
最后,请注意,低延迟模式不是一个保证。如果GC在做回收的时候仍然抛出了OutOfMemoryException异常,仍然有可能会不管你的配置选项,进行一次完整的GC回收。
[翻译] 编写高性能 .NET 代码--第二章 GC -- 配置选项的更多相关文章
- [翻译] 编写高性能 .NET 代码--第二章 GC -- 减少分配率, 最重要的规则,缩短对象的生命周期,减少对象层次的深度,减少对象之间的引用,避免钉住对象(Pinning)
减少分配率 这个几乎不用解释,减少了内存的使用量,自然就减少GC回收时的压力,同时降低了内存碎片与CPU的使用量.你可以用一些方法来达到这一目的,但它可能会与其它设计相冲突. 你需要在设计对象时仔细检 ...
- [翻译] 编写高性能 .NET 代码--第二章 GC -- 避免使用终结器,避免大对象,避免复制缓冲区
避免使用终结器 如果没有必要,是不需要实现一个终结器(Finalizer).终结器的代码主要是让GC回收非托管资源用.它会在GC完成标记对象为可回收后,放入一个终结器队列里,在由另外一个线程执行队列里 ...
- [翻译] 编写高性能 .NET 代码--第二章 GC -- 将长生命周期对象和大对象池化
将长生命周期对象和大对象池化 请记住最开始说的原则:对象要么立即回收要么一直存在.它们要么在0代被回收,要么在2代里一直存在.有些对象本质是静态的,生命周期从它们被创建开始,到程序停止才会结束.其它对 ...
- [翻译] 编写高性能 .NET 代码--第二章 GC -- 减少大对象堆的碎片,在某些情况下强制执行完整GC,按需压缩大对象堆,在GC前收到消息通知,使用弱引用缓存对象
减少大对象堆的碎片 如果不能完全避免大对象堆的分配,则要尽量避免碎片化. 对于LOH不小心就会有无限增长,但LOH使用的空闲列表机制可以减轻增长的影响.利用这个空闲列表,我们可以在两块分配区域中间找到 ...
- [翻译]编写高性能 .NET 代码 第二章:垃圾回收
返回目录 第二章:垃圾回收 垃圾回收是你开发工作中要了解的最重要的事情.它是造成性能问题里最显著的原因,但只要你保持持续的关注(代码审查,监控数据)就可以很快修复这些问题.我这里说的"显著的 ...
- [翻译]编写高性能 .NET 代码 第二章:垃圾回收 基本操作
返回目录 基本操作 垃圾回收的算法细节还在不断完善中,性能还会有进一步的提升.下文介绍的内容在不同的.NET版本里会略有不同,但大方向是不会有变动的. 在.net进程里会管理2个类型的内存堆:托管和非 ...
- [翻译]编写高性能 .NET 代码 第一章:性能测试与工具 -- 平均值 vs 百分比
<<返回目录 平均值 vs 百分比 在考虑要性能测试的目标值时,我们需要考虑用什么统计口径.大多数人都会首选平均值,但在大多数情况下,这个正确的,但你也应该适当的考虑百分数.但你有可用性的 ...
- [翻译]编写高性能 .NET 代码 第一章:工具介绍 -- Visual Studio
<<返回目录 Visual Studio vs虽然不是全宇宙唯一的IDE,但它是.net开发人员最常用的开发工具.它自带一个性能分析工具,你可以使用它来做开发,不同的vs版本在工具上会略有 ...
- [翻译]编写高性能 .NET 代码 第一章:工具介绍 -- Performance Counters(性能计数器)
<<返回目录 Performance Counters(性能计数器) 性能计数器是监视应用程序和系统性能的最简单的方法之一.它有几十个类别数百个计数器在,包括一些.net特有的计数器.要访 ...
随机推荐
- Oracle问题之ORA-01609、ORA-00362
Oracle问题之ORA-01609: 日志 4 是线程 1 的当前日志 - 无法删除成员 Oracle问题之ORA-00362: 要求输入成员以组成组 4 中的有效日志文件
- Qt出现堆溢出(Error Code -1073741823)
症状 在使用Debug模式时,程序可以正常启动,但是切换到Release模式,程序报错,错误码-1073741823 原因 程序中使用了过多的new.比如: QActionGroup *mProtoc ...
- Git工具的使用教程
Git 是一种版本控制工具,也叫作版本管理软件(分布式管理软件).这里介绍Git的基本使用步骤,关于 Git 更详细的介绍,读者可以参考其官方网站提供的文档. 1 安装Git 在Ubuntu系统中安 ...
- AI_神经网络监督学习
神经网络的神奇之处在哪? 所有神经网络创造出来的价值,都是由一种机器学习,称之为监督学习, 下面这些例子神经网络效果拔群,通过深度学习获利最多的是在线广告 技术的进步来源于计算机视觉和深度学习 例如: ...
- Django_form验证
需求: 当用户向Django后端以post提交数据的时候,无论前端是否进行数据合法验证,后端都需要对客户端提交过来的数据进行数据合法性验证,是否可以利用models中表类字段的约束来实现验证,并且可以 ...
- eclipse:Workspace in use or cannot be created
打开eclipse出现:Workspace in use or cannot be created, choose a different one 原因:出现这种情况一般是workspace的配置文件 ...
- 流API--分组和分片
分组和分片 对具有相同特性的值进行分组时一个很常见的任务,我们可以直接使用groupingBy来进行分组. 当分类函数是一个predicate函数时,流会被分成2组列表,一组返回true,一组返回fa ...
- 【Java框架型项目从入门到装逼】第十四节 查询用户列表展现到页面
这一节,我们来实现一下用户列表搜索,最终的效果如下: 这边我们要使用easyUI给我们提供的datagrid组件. HTML结构如下 <!-- 数据列表 --> <table id= ...
- Arrays.sort解析
Arrays.sort()解读 在学习了排序算法之后, 再来看看 Java 源码中的, Arrays.sort() 方法对于排序的实现. 都是对基本数据类型的排序实现, 下面来看看这段代码: Arra ...
- $.ajax()实现简单计算器
1.html页面 a.html <!DOCTYPE html> <html lang="en"> <head> <meta charse ...