[翻译] 编写高性能 .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特有的计数器.要访 ...
随机推荐
- Java面试经
最近趁有空整理下面试经常会被问到的知识点,参考的资料都是本人通过百度而挑选出来的,具有一定的参考意义. 一 .java基础1.String和StringBuffer.StringBuild的区别:ht ...
- HX711初步处理记录
参考文档为极客工坊大神记录 http://www.geek-workshop.com/forum.php?mod=viewthread&tid=2315&highlight=hx711 ...
- 两层嵌套list,选取list中最长的list的长度
# coding=utf-8 import pandas as pd file_path = "test_aa.xlsx" dt = pd.read_excel(file_path ...
- Ubuntu 11.10 Server下搭建Maven私服
安装Nexus服务的文档可以参考官方站点:http://www.sonatype.com/books/nexus-book/reference/install-sect-install.html ...
- Linux指令--rm, rmdir
rm是常用的命令,该命令的功能为删除一个目录中的一个或多个文件或目录,它也可以将某个目录及其下的所有文件及子目录均删除.对于链接文件,只是删除了链接,原有文件均保持不变.rm是一个危险的命令,使用的时 ...
- TinyXML 的简单介绍以及使用
先说几句重点: 1,tinyxml 生成或解析XML非常好用 2,tinyxml 利用DOM(文档对象模型)操作XML,根节点与各个子节点相当于形成一棵树 3,只要你了解tinyxml的用法,可以只n ...
- JSP -java service pages
jsp的运行机制: 1客户端(请求jsp页面)------->JSP页面(转换为java源文件)------->Selvet文件(.java) (编译成相应的字节码文件也就是后缀名是.cl ...
- awk 里的substr()
awk 里的substr函数用法举例: 要截取要截取的内容1: F115!16201!1174113017250745 10.86.96.41 211.140.16.1 200703180718F12 ...
- Notepad++运行Java
插件NppExec使用 首先要让Notepad++编译和运行Java,前提是电脑里已经配置好了Java的环境 1,安装插件NppExec:解压出来提取NppExec.dll文件放在Notepad++安 ...
- 集中式(SVN)和分布式(Git)版本控制系统的简单比较
集中式(SVN) 分布式(Git) 是否有中央服务器 有.开发人员需要从中央服务器获得最新版本的项目然后在本地开发,开发完推送给中央服务器.因此脱离服务器开发者是几乎无法工作的 没有中央 ...