我正在设计一个数据结构,它可以执行大量的对象分配以执行其功能。添加一百万个项目大约需要500毫秒。
我一直在寻找优化其功能的方法,并且只是让它变得更快,我觉得我已经用尽了其他提高性能的潜在方法。
在阅读有关垃圾收集的内容时,我注意到有一个启用服务器垃圾收集的选项,并且我只是将其设置为true,这导致运行时间从500毫秒变为200毫秒:这是一个令人难以置信的改进! / p>
我读到它使用多个内核来运行垃圾收集器。我想知道几件事。现在大多数人都有多核系统,为什么默认不包含这个系统?另外,如果我将我的数据结构打包为DLL,默认情况下是否可以启用此功能,可能仅适用于我的库,而不是客户端更喜欢的其他应用程序?
我有一种感觉我真的无法利用这种力量,但也许有一种方法可以从中窃取一些技术并将其以某种方式融入我自己的程序中?服务器垃圾收集如此快速?是不是它使用了多个核心,或者是否有其他功能可以在我自己的代码中克隆?
答案 0 :(得分:3)
服务器GC的转换方式与工作站GC完全不同。它对机器类型和应用类型做出了截然不同的假设。 Web服务器将是典型的示例。运行相对强大的硬件,具有大量内存和具有大量内核的不错处理器。并且是在机器上运行的唯一应用程序,因此几乎可以要求使用机器的所有资源。
Workstation GC经过调整,可以在桌面上的机器上运行良好。你运行了许多程序并讨厌它,当其中一个程序让你的鼠标缓慢响应,因为程序是霸气的处理器和磁盘。当程序停止响应一段时间因为忙于收集垃圾时,你不喜欢它。
集合暂停曾经是最重要的选择器,工作站GC始终对在后台执行繁重的集合提供了不错的支持。所以该计划保持响应。这已经不再那么重要了,服务器GC获得了在.NET 4.5中进行后台收集的能力
分析很棘手,请确保您不会被服务器GC的另一个方面误导。它创建了更大的堆段。因此,很容易分析您的代码并找到一个快乐的数字,其中代码的执行不会被一个或多个第2代第2集合中断。 不意味着您将始终如一地获得此效果,迟早您必须付出代价。背景集合只有在你不需要第2代集合时才能很好地工作,但是当背景集合在它上面时,它可以在第0代和第1集合中很好地生存。换句话说,您制作的大量集合需要用于短期对象。不是你的代码,而是它的声音。
负责任的分析需要的质量不是很多程序员所拥有的,你必须准备好大步走坏消息并假设玻璃杯是空的。多次运行测试,而不仅仅是一次。避免启动和初始化工件。并将测量的中值作为测量结果。着眼于最糟糕的情况。而忽略最好的,你可以依靠在实践中复制。最好将它构建到最终的软件中,这样你总能得到真实的数字,PerformanceCounter对此有好处。
答案 1 :(得分:0)
new
是一项相当昂贵的操作,无论它的优化程度如何,并且
每次分配一块内存时,迟早都需要收集它。一个常见的技巧是在每个块中包含一个前向指针(对不起,引用),只要你知道你不再需要一个块,而不是放弃它,你就把它链接到一个< em>该类型块的免费列表。
然后当你需要一个时,首先看一下自由列表中是否有任何内容。
如果是这样,请使用它而不是new
。
这样,您可以避免大部分new
及其相应的GC。
如果您确定new
(因此GC)占用了大部分挂钟时间,那么这是值得做的。
我确定的方式是random pausing。
答案 2 :(得分:0)
现在大多数人都拥有多核系统,为什么默认情况下不包括这个系统?
工作站GC默认在工作站(Win7 / 8 / XP,Consumer OSes)上启用。默认情况下,服务器操作系统上启用了服务器GC(Windows Server 2003,2012等)。 GC启动前工作站的内存使用量下限。根据您的代码(未显示),您对服务器GC模式的限制尚未达到该限制,并且可能尚未启动GC。请参阅MSDN上的Comparing workstation and server GC modes部分。
另外,如果我将我的数据结构打包为DLL,默认情况下是否可以启用此功能,可能仅适用于我的库而不是客户端更喜欢的其他应用程序?
这可以通过app / web.config文件进行控制。客户端总是可以覆盖它。但是您可以通过GCSettings.IsServerGC
属性检测到它并抛出异常或警告,但我强烈建议不要这样做。如果系统上只有1个CPU,则.NET运行时可以覆盖这些配置设置。
我一直在寻找优化其功能的方法,并且只是让它变得更快,我觉得我已经用尽了其他提高性能的潜在方法。
查看预分配对象或重新使用相同的对象分配。例如,许多.NET集合都有一个内部数组,可以提前预先调整大小,以减少随着更多对象添加到集合中而必须发生的内存副本数量。