简体   繁体   English

.net集合内存优化 - 这种方法会起作用吗?

[英].net collections memory optimization - will this method work?

Just like almost any other big .NET application, my current C# project contains many .net collections . 就像几乎任何其他大型.NET应用程序一样,我当前的C#项目包含许多.net集合。
Sometimes I don't know, from the beginning, what the size of a Collection (List/ObservableCollection/Dictionary/etc.) is going to be. 有时我从一开始就不知道Collection(List / ObservableCollection / Dictionary / etc。)的大小是多少。
But there are many times when I do know what it is going to be. 但是很多时候我确实知道它会是什么。

I often get an OutOfMemoryException and I've been told it can happen not only because process size limits, but also because of fragmentation. 我经常得到一个OutOfMemoryException并且我被告知它不仅可能因为进程大小限制而且还因为碎片而发生。

So my question is this - will setting collection's size (using the capacity argument in the constructor) every time I know its expected size help me prevent at least some of the fragmentation problems ? 所以我的问题是 - 每当我知道它的预期大小帮助我防止至少一些碎片问题时,将设置集合的大小(使用构造函数中的capacity参数)吗?

This quote is from the msdn : 这句话来自msdn

If the size of the collection can be estimated, specifying the initial capacity eliminates the need to perform a number of resizing operations while adding elements to the List. 如果可以估计集合的大小,则指定初始容量消除了在向List添加元素的同时执行大量调整大小操作的需要。

But still, I don't want to start changing big parts of my code for something that might not be the real problem. 但是,我仍然不想开始更改我的代码的大部分内容,因为这可能不是真正的问题。

Has it ever helped any of you to solve out of memory problems ? 它有没有帮助你们解决内存不足的问题?

Specifying an initial size will rarely if ever get rid of an OutOfMemory issue - unless your collection size is millions of object in which case you should really not keep such a collection. 如果摆脱OutOfMemory问题,指定初始大小很少 - 除非你的集合大小是数百万的对象,在这种情况下你真的不应该保留这样的集合。

Resizing a collection involves defining a completely new array with a new additional size and then copying the memory. 调整集合大小涉及使用新的附加大小定义一个全新的数组,然后复制内存。 If you are already close to out of memory, yes, this can cause an out of memory since the new array cannot be allocated. 如果您已经接近内存不足,是的,这可能会导致内存不足,因为无法分配新阵列。

However, 99 out of 100, you have a memory leak in your app and collection resizing issues is only a symptom of it. 但是,在100个中有99个,您的应用程序中存在内存泄漏,并且收集调整大小问题只是其中的一个症状。

If you are hitting OOM, then you may be being overly aggressive with the data, but to answer the question: 如果您正在使用OOM,那么您可能对数据过于激进,但要回答这个问题:

Yes, this may help some - as if it has to keep growing the collections by doubling, it could end up allocating and copying twice as much memory for the underlying array (or more precicely, for the earlier smaller copies that are discarded). 是的,这可能会帮助一些 -因为它必须保持加倍增长的集合,它可能最终分配和底层数组复制两倍的内存(或更多precicely,为被丢弃的早期小份)。 Most of these intermediate arrays will be collected promptly, but when they get big you are using the "large object heap", which is harder to compact. 大多数这些中间阵列都会被迅速收集,但是当它们变大时,你会使用“大对象堆”,这很难压缩。

Starting with the correct size prevents all the intermediate copies of the array. 从正确的大小开始可以防止阵列的所有中间副本。

However, it also depends what is in the array matters. 不过,这也要看是什么阵列事项。 Typically, for classes, there is more data in each object (plus overheads for references etc) - meaning the list is not necessarily the biggest culprit for memory use; 通常,对于类, 每个对象中都有更多数据(加上引用的开销等) - 这意味着列表不一定是内存使用的最大罪魁祸首; you might be burning up most of the memory on objects. 你可能会烧掉对象上的大部分内存。

Note that x64 will allow more overall space, but arrays are limited to 2GB - and if each reference doubles in size this halves the maximum effective length of the array. 请注意,x64将允许更多的整体空间,但数组限制为2GB - 如果每个引用的大小增加一倍,则会将数组的最大有效长度减半。

Personally I would look at breaking the huge sets into smaller chains of lists; 就个人而言,我会把大集合打成更小的列表 ; jagged lists, for example. 例如,参差不齐的列表。

.NET has a compating garbage collector, so you probably won't run into fragmentation problems on the normal .NET heap. .NET有一个竞争垃圾收集器,所以你可能不会在正常的.NET堆上遇到碎片问题。 You can however get memory fragmentation if you're using lots of unmanaged memory (eg through GDI+, COM, etc.). 但是,如果您使用大量非托管内存(例如通过GDI +,COM等),则可能会出现内存碎片。 Also, the large object heap isn't compacted, so that can get fragmented, too. 此外,大型对象堆不会被压缩,因此也可能会碎片化。 IIRC an object is put into the LOH if it's bigger than 80kb. IIRC如果物体大于80kb,则将物体放入LOH。 So if you have many collections that contain more than 20k objects, you might get fragmentation problems. 因此,如果您有许多包含超过20k对象的集合,则可能会出现碎片问题。

But instead of guessing where the problem might be, it might be better to narrow the problem down some more: When do you get the OutOfMemoryExceptions? 但是,不要猜测问题可能在哪里,可能更好地将问题缩小到更多:何时获得OutOfMemoryExceptions? How much memory is the application using at that time? 当时应用程序使用了多少内存? Using a tool like WinDbg or memory profilers you should be able to find out how much of that memory is on the LOH. 使用像WinDbg或内存分析器这样的工具,您应该能够找出LOH上有多少内存。

That said, it's always a good idea to set the capacity of List and other data structures in advance if you know it. 也就是说,如果你知道的话,提前设置List和其他数据结构的容量总是一个好主意。 Otherwise, the List will double it's capacity everytime you add an item and hit the capacity limit which means lots of unnecessary allocation and copy operations. 否则,每次添加项目并达到容量限制时,列表将使其容量加倍,这意味着许多不必要的分配和复制操作。

In order to solve this, you have to understand the basics and pinpoint the problem in your code. 为了解决这个问题,您必须了解基础知识并查明代码中的问题。

It is always a good idea to set the initial capacity, if you have a sensible estimate. 如果您有合理的估计值,那么设置初始容量始终是个好主意。 If you only have an approximate guess, allocate more. 如果您只有近似猜测,请分配更多。

Fragmentation can only occur on the LOH (objects over 80 kB). 碎片只能在LOH(超过80 kB的对象)上发生。 To prevent it , try to allocate blocks of the same size. 要防止它,请尝试分配相同大小的块。 Paradoxically, the solution might be to sometimes allocate more memory than you actually need. 矛盾的是,解决方案可能有时会分配比实际需要更多的内存。

The answer is that, yes pre-defining a size on collections will increase performance and memory optimization and reduce fragmentation. 答案是,是的,预先定义集合的大小将提高性能和内存优化并减少碎片。 See my answer here to see why - If I set the initial size of a .NET collection and then add some items OVER this initial size, how does the collection determine the next resize? 请参阅我的答案,了解原因 - 如果我设置.NET集合的初始大小,然后添加一些超过此初始大小的项目,集合如何确定下一次调整大小?

However, without analyzing a memory dump or memory profiling on the app, it's impossible to say exactly what the cause of the OOM is. 但是,如果不分析应用程序上的内存转储或内存分析,就不可能确切地说出OOM的原因是什么。 Thus, impossible to conjecture if this optimization will solve the problem. 因此,如果这种优化能够解决问题,就不可能推测出来。

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

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