简体   繁体   English

GC与C#和C ++在同一解决方案中

[英]GC with C# and C++ in same solution

I have a solution consisting of a number of C# projects. 我有一个由许多C#项目组成的解决方案。 It was written in C# to get it operational quickly. 它是用C#编写的,以使其快速运行。 Garbage collections are starting to become an issue—we are seeing some 100 ms delays that we'd like to avoid. 垃圾收集开始成为一个问题 - 我们正在看到我们想要避免的100毫秒延迟。

One thought was to re-write it in C++, project by project. 一种想法是用C ++重新编写它,逐个项目。 But if you combine C# with unmanaged C++, will the threads in the C++ projects also be frozen by garbage collections? 但是,如果将C#与非托管C ++结合使用,C ++项目中的线程是否也会被垃圾收集冻结?

UPDATE UPDATE

Thanks for your replies. 谢谢你的回复。 This is, in fact, an app where 100 ms might be significant. 事实上,这是一个100毫秒可能很重要的应用程序。 It was probably a poor decision to build it in C#, but it was essential that it be up and running quickly at the time. 在C#中构建它可能是一个糟糕的决定,但它必须在当时快速启动并运行。

Right now, we're using Windows' Multimedia Timers to fire an event every 5 ms. 现在,我们正在使用Windows的多媒体计时器每隔5毫秒触发一次事件。 We do see some 100+ ms gaps, and we've confirmed by checking the GC counters that these always occur during a collection. 我们确实看到了100多个ms的间隙,我们通过检查GC计数器确认这些间隙总是在收集期间发生。 Optimization is on; 优化正在进行; built in Release mode. 内置于发布模式。

I work as a .NET developer at a trading firm where, like you, we care about 100 ms delays. 我在一家贸易公司担任.NET开发人员,与您一样,我们关心100毫秒的延迟。 Garbage collection can indeed become a significant issue when dependable minimal latency is required. 当需要可靠的最小延迟时,垃圾收集确实会成为一个重要问题。

That said, I don't think migrating to C++ is going to be a smart move, mainly due to how time consuming it would be. 也就是说,我不认为迁移到C ++会是一个聪明的举动,主要是因为它会耗费多少时间。 Garbage collection occurs after a certain amount of memory has been allocated on the heap over time. 在堆上分配了一定量的内存后,会发生垃圾收集。 You can substantially mitigate this issue by minimizing the amount of heap allocation your code creates. 您可以通过最小化代码创建的堆分配量来大大缓解此问题

I'd recommend trying to spot methods in your application that are responsible for significant amounts of allocation. 我建议您尝试在应用程序中发现负责大量分配的方法。 Anywhere objects are constructed is going to be a candidate for modification. 构建Anywhere对象将成为修改的候选对象。 A classic approach to fighting garbage collection is utilizing resource pools : instead of creating a new object every time a method is called, maintain a pool of already-constructed objects, borrowing from the pool on every method call and returning the object to the pool once the method has completed. 打击垃圾收集的经典方法是利用资源池 :不是每次调用方法时都创建新对象,而是维护已构造对象池,在每次方法调用时从池中借用并将对象返回到池中该方法已经完成。

Another no-brainer involves hunting down any ArrayList , HashTable , or similar non-generic collections in your code that box/unbox value types, leading to totally unnecessary heap allocation. 另一个明智的做法是在代码中搜索任何ArrayListHashTable或类似的非泛型集合,这些集合是box / unbox值类型,导致完全不必要的堆分配。 Replace these with List<T> , Dictionary<TKey, TValue> , and so on wherever possible (here I am specifically referring to collections of value types such as int , double , long , etc.). 尽可能用List<T>Dictionary<TKey, TValue>替换它们(这里我特指的是值类型的集合,如intdoublelong等)。 Likewise, look out for any methods you may be calling which box value type arguments (or return boxed value types). 同样,请注意您可能正在调用哪些方法值类型参数(或返回盒装值类型)。

These are just a couple of relatively small steps you can take to reducing your garbage collection count, but they can make a big difference. 这些只是您可以采取的几个相对较小的步骤来减少垃圾收集计数,但它们可以产生很大的不同。 With enough effort it can even be possible to completely (or at least nearly ) eliminate all generation 2 garbage collections during the continuous operations phase (everything except for startup and shutdown) of your application. 通过足够的努力,甚至可以在应用程序的连续操作阶段(除了启动和关闭之外的所有阶段)完全(或至少几乎 )消除所有第2代垃圾收集。 And I think you'll find that generation 2 collections are the real heavy-hitters. 而且我认为你会发现第2代系列是真正的重击手。

Here's a paper outlining one company's efforts to minimize latency in a .NET application through resource pooling, in addition to a couple of other methods, with great success: 这篇文章概述了一家公司通过资源池最小化.NET应用程序延迟的努力,以及其他几种方法,并取得了巨大成功:

Rapid Addition leverages Microsoft .NET 3.5 Framework to build ultra-low latency FIX and FAST processing Rapid Addition利用Microsoft .NET 3.5 Framework构建超低延迟的FIX和FAST处理

So to reiterate: I would strongly recommend investigating ways to modify your code so as to cut down on garbage collection over converting to an entirely different language. 所以重申:我强烈建议调查修改代码的方法,以便减少垃圾收集而不是转换为完全不同的语言。

First, have you tried profiling things to see if you could optimize your memory usage? 首先,您是否尝试过分析事物以查看是否可以优化内存使用量? A good place to start is with the CLR profiler (works with all CLRs up to 3.5). 一个好的起点是使用CLR分析器 (适用于最高3.5的所有CLR)。

Rewriting everything in C++ is an incredibly drastic change just for the sake of a small performance hit -- this is like fixing a paper cut by amputating your hand. 用C ++重写所有东西是一个令人难以置信的巨大变化,只是为了小的性能打击 - 这就像通过截断你的手来修复剪纸一样。

Are you certain that those 100ms delays are due to the GC? 您确定那些100毫秒延迟是由于GC造成的吗? I would make VERY sure that the GC really is your problem before you spend a lot of time, effort, and money rewriting the thing in C++. 在你花费大量的时间,精力和金钱重写C ++中的东西之前,我会非常确定GC确实是你的问题。 Combining managed code with unmanaged code also presents its own problems, as you have to deal with marshalling between those two contexts. 将托管代码与非托管代码相结合也会出现问题,因为您必须处理这两个上下文之间的编组。 That will add its own performance drain, and your net gain could quite likely end up being zero in the end. 这将增加其自身的性能消耗,并且您的净收益最终很可能最终为零。

I would profile your C# application and narrow down exactly where your 100ms delays are coming from. 我会描述你的C#应用​​程序,并缩小你的100ms延迟的确切位置。 This tool might be helpful: 此工具可能会有所帮助:

How To: Use CLR Profiler 如何:使用CLR Profiler

A word on the GC 关于GC的一个词

Another word about the .NET GC (or really any GC, for that matter.) This one is not nearly said often enough, but it is a critical factor in successfully writing code with a GC: 关于.NET GC的另一个词(或者实际上任何GC,就此而言。)这个经常说不够,但它是用GC成功编写代码的关键因素:

Having a Garbage Collector does not mean you don't have to think about memory management! 有一个垃圾收集并不意味着你不必考虑内存管理!

Writing optimal code that plays nicely with the GC requires less effort and hassle than writing C++ code that plays nicely with an unmanaged heap...but you still have to understand the GC and write code that plays nicely with the it. 编写与GC完美匹配的最佳代码比编写与非托管堆良好匹配的C ++代码需要更少的工作量和麻烦......但是您仍然必须理解GC并编写与其良好匹配的代码。 You can't completely ignore all memory management related things. 您不能完全忽略所有与内存管理相关的事情。 You have to worry about it less, but you still have to think about it. 你不得不担心它,但你仍然需要考虑它。 Writing code that plays nicely with the GC is a critically important factor in achieving performant code that does not CREATE memory management problems. 编写与GC完美匹配的代码是实现不会产生内存管理问题的高性能代码的一个至关重要的因素。

The following article should also be helpful, as it outlines the fundamental behaivor of the .NET GC (valid through .NET 3.5...its quite likely that this article is no longer completely valid for .NET 4.0 as there have been some critical changes to its GC...for one, it no longer has to block .NET threads while collection occurs): 下面的文章也应该有所帮助,因为它概述了.NET GC的基本行为(通过.NET 3.5有效...很可能本文不再完全适用于.NET 4.0,因为有一些关键的变化到它的GC ...对于一个,它不再需要在收集时阻止.NET线程):

Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework 垃圾收集:Microsoft .NET Framework中的自动内存管理

The CLR GC does not suspend threads running unmanaged code during a collection. CLR GC不会在集合期间挂起运行非托管代码的线程。 If the native code calls into managed code, or returns to managed code then it may be affected by a collection (like any other managed code). 如果本机代码调用托管代码,或返回托管代码,那么它可能会受到集合的影响(就像任何其他托管代码一样)。

If 100 ms is an issue, I asusme your code is mission critical. 如果100毫秒是一个问题,我asusme您的代码是关键任务。 Mixing managed and unmanaged code will have interop overhead of calling between managed appdomain and unmanaged space. 混合托管和非托管代码将在托管应用程序域和非托管空间之间进行调用。

GC is very well optimized, so before doing that try to profile your code and refactor it. GC已经过优化,所以在此之前尝试分析您的代码并重构它。 If you are concerned about GC, try playing with setting the thread priority and minimize object creation and cache the data whenever possible. 如果您担心GC,请尝试使用设置线程优先级并尽可能减少对象创建并尽可能缓存数据。 In your project property turns on Optimize code setting too. 在您的项目中,属性也会启用Optimize代码设置。

One thought was to re-write it in C++, project by project. 一种想法是用C ++重新编写它,逐个项目。 But if you combine C# with unmanaged C++, will the threads in the C++ projects also be frozen by garbage collections? 但是,如果将C#与非托管C ++结合使用,C ++项目中的线程是否也会被垃圾收集冻结?

Not if the C++ code is running on different threads. 如果C ++代码在不同的线程上运行则不行。 the C++ heap and the managed heap are different things. C ++堆和托管堆是不同的东西。

On the other hand, if your C++ code is doing a lot of new/delete, you will still begin to see allocation stalls in the C++ code as the heap gets to be fragmented. 另一方面,如果您的C ++代码执行了大量的新/删除操作,那么当堆变为碎片时,您仍将开始在C ++代码中看到分配停顿。 And these stalls are likely to be much worse than what you see in C# code because there is no GC. 这些档位可能比你在C#代码中看到的糟糕得多,因为没有GC。 When the heap needs to be cleaned up, it just happens inside the call to new or delete. 当需要清理堆时,它只发生在对new或delete的调用中。

If you really have a tight performance requirement, then you need to plan on not doing any memory allocation from the general heap inside your time critical code. 如果您确实有严格的性能要求,那么您需要计划不在时间关键代码中的常规堆中进行任何内存分配。 In practice that means this will be more like C code than C++ code, or using special memory pools and placement new. 在实践中,这意味着这将更像C代码而不是C ++代码,或者使用特殊的内存池和新的放置。

.NET 4.0 has what's called Background Garbage Collection , which is different than Concurrent Garbage Collection , which may be what is causing your issue. .NET 4.0具有所谓的背景垃圾收集 ,它与并发垃圾收集不同,它可能是导致您的问题的原因。 Jason Olson talks about it with Carl Franklin and Richard Campbell on .NET Rocks Episode #517 . Jason Olson与Carl Franklin和Richard Campbell就.NET Rocks 第517集进行了讨论 You can view the transcript here . 你可以在这里查看成绩单。 It's on page 5. 它在第5页。

I'm not completely sure if just upgrading to the 4.0 Framework will solve your problem, but I imagine it would be well worth your time looking into it before rewriting everything in C++. 我不完全确定是否只是升级到4.0 Framework会解决你的问题,但我想在你用C ++重写所有内容之前考虑它是值得的。

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

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