简体   繁体   English

.NET GC 停止桌面应用程序 - 性能问题

[英].NET GC Stalling Desktop Application - Performance Issue

I am working on a large windows desktop application that stores large amount of data in form of a project file.我正在开发一个大型 Windows 桌面应用程序,该应用程序以项目文件的形式存储大量数据。 We have our custom ORM and serialization to efficiently load the object data from CSV format.我们有我们的自定义 ORM 和序列化来有效地从 CSV 格式加载对象数据。 This task is performed by multiple threads running in parallel processing multiple files.此任务由并行处理多个文件的多个线程执行。 Our large project can contain million and likely more objects with many relationships between them.我们的大型项目可以包含数百万甚至更多的对象,它们之间有许多关系。

Recently I got tasked to improve the project open performance which deteriorated for very large projects.最近,我的任务是提高项目的开放性能,而这在非常大的项目中会恶化。 Upon profiling it turned out that most of the time spent can be attributed to garbage collection (GC).分析后发现,大部分时间都花在了垃圾收集 (GC) 上。

My theory is that due to large number of very fast allocations the GC is starved, postponed for a very long time and then when it finally kicks in it takes a very long time to the job.我的理论是,由于大量非常快的分配,GC 被饿死,推迟了很长时间,然后当它最终启动时,它需要很长时间才能完成工作。 That idea was further confirmed by two contradicting facts:两个相互矛盾的事实进一步证实了这一想法:

  1. Optimizing deserialization code to work faster only made things worse优化反序列化代码以加快工作速度只会让事情变得更糟
  2. Inserting Thread.Sleep calls at strategic places made load go faster在关键位置插入Thread.Sleep调用使加载速度更快

Example of slow load with 7 generation 2 collections and huge % of time in GC is below.下面是第 7 代第 2 代收集和大量 GC 时间的缓慢加载示例。 坏的

Example of fast load with sleep periods in the code to allow GC some time is below.下面是代码中带有睡眠周期以允许 GC 一段时间的快速加载示例。 In this case wee have 19 generation 2 collections and also more than double the number of generation 0 and generation 1 collections.在这种情况下,我们有 19 个第 2 代集合,并且第 0 代和第 1 代集合的数量增加了一倍以上。 好的

So, my question is how to prevent this GC starvation?所以,我的问题是如何防止这种 GC 饥饿? Adding Thread.Sleep looks silly and it is very difficult to guess the right amount of milliseconds in the right place.添加Thread.Sleep看起来很傻,而且很难在正确的位置猜测正确的毫秒数。 My other idea would be to use GC.Collect , but that also poses the difficulty of how many and where to put them.我的另一个想法是使用GC.Collect ,但这也带来了放置它们的数量和位置的困难。 Any other ideas?还有其他想法吗?

Based on the comments, I'd guess that you are doing a ton of String.Substring() operations as part of CSV parsing.根据评论,我猜您正在执行大量String.Substring()操作作为 CSV 解析的一部分。 Each of these creates a new string instance, which I'd bet you then throw away after further parsing it into an integer or date or whatever you need.每一个都创建了一个新的字符串实例,我敢打赌,在进一步将其解析为整数或日期或您需要的任何内容后,您将其丢弃。 You almost certainly need to start thinking about using a different persistence mechanism (CSV has a lot of shortcomings that you are undoubtedly aware of), but in the meantime you are going to want to look into versions of parsers that do not allocate substrings.您几乎肯定需要开始考虑使用不同的持久性机制(CSV 有很多您无疑知道的缺点),但与此同时,您将要查看不分配子字符串的解析器版本。 If you dig into the code for Int32.TryParse, you'll find that it does some character iteration to avoid allocating more strings.如果您深入研究 Int32.TryParse 的代码,您会发现它进行了一些字符迭代以避免分配更多的字符串。 I'd bet that you could spend an hour writing a version that takes a start and end parameter, then you can pass them the whole line with offsets and avoid doing a substring call to get the individual field values.我敢打赌,您可以花一个小时来编写一个接受startend参数的版本,然后您可以将整行与偏移量一起传递给它们,并避免进行子字符串调用来获取各个字段值。 Doing that will save you millions of allocations.这样做将为您节省数百万的分配。

So, it appears that this is a .NET bug rather then GC starvation.因此,这似乎是一个 .NET 错误,而不是 GC 饥饿。 The workarounds and answers described in this question Garbage Collection and Parallel.ForEach Issue After VS2015 Upgrade apply perfectly.这个问题垃圾收集和 Parallel.ForEach Issue After VS2015 Upgrade 中描述的解决方法和答案完全适用。 I got best results by switching to GC server mode.我通过切换到 GC 服务器模式获得了最佳结果。

Note however, that I am experiencing this issue in .NET 4.5.2.但是请注意,我在 .NET 4.5.2 中遇到了这个问题。 Will add hotfix link if there is one.如果有,将添加修补程序链接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM