【发布时间】:2015-11-03 16:22:00
【问题描述】:
我正在开发一个大型 Windows 桌面应用程序,它以项目文件的形式存储大量数据。我们有我们的自定义 ORM 和序列化来有效地从 CSV 格式加载对象数据。此任务由并行运行的多个线程执行,处理多个文件。我们的大型项目可以包含数百万甚至更多的对象,它们之间有许多关系。
最近,我的任务是改善大型项目的项目开放性能,这种性能会恶化。分析后发现,大部分时间都花在垃圾收集 (GC) 上。
我的理论是,由于大量非常快速的分配,GC 被饿死了,被推迟了很长时间,然后当它最终启动时,它需要很长时间才能完成工作。两个相互矛盾的事实进一步证实了这一想法:
- 优化反序列化代码以更快地工作只会让事情变得更糟
- 在战略位置插入
Thread.Sleep呼叫可以加快负载速度
下面是第 7 代第 2 代收集的缓慢加载和大量 GC 时间的示例。
下面是代码中带有休眠期的快速加载示例,以允许 GC 一些时间。在这种情况下,我们有 19 个第 2 代集合,并且也是第 0 代和第 1 代集合的两倍多。
那么,我的问题是如何防止这种 GC 饥饿?添加Thread.Sleep 看起来很傻,很难在正确的位置猜出正确的毫秒数。我的另一个想法是使用GC.Collect,但这也带来了放置数量和放置位置的困难。还有其他想法吗?
【问题讨论】:
-
我想知道 Thread.Sleep 如何/为什么让事情变得更快?快多少?
-
我在创建大量重复字符串变量然后作为序列化的一部分取消引用的情况下看到了这种类型的行为。你使用什么样的序列化来加载项目文件?
-
所有加载都是在后台线程上完成的,所以我假设 sleep 允许 GC 线程启动。从上面的图片你可以看到,一旦我们引入睡眠,我们会从 4 分钟缩短到 25 秒。减速以加快速度:)
-
GC 由分配触发。如果您在此期间休眠,则不会触发 GC。我发现 GC 饥饿理论的证据非常薄弱。
-
@HansPassant 在 cmets 中查找该问题的答案 - 看起来该错误已通过修补程序 stackoverflow.com/a/31999381/4450618 修复
标签: c# .net garbage-collection desktop-application