.NET - what is GC'd faster: few large objects or many small objects?
For example, if I'm anyway doomed to allocate 100Mb of memory per second that will almost immediately become useless, will it be faster to GC if allocated in chunks of 500kb or 500b?
Larger chunks probably get into the Large Object Heap - should that decrea开发者_开发问答se performance?
Definitely avoid the large object heap - that means anything over 85000 bytes.
Update to explain some things and answer your comment
My instincts say to go for the largest object size you can and still avoid the large object heap. The reason is the same as other answers — fewer objects ostensibly means a simply, shorter collection cycle. The reason I want to avoid the LOH is because of compaction issues for a long running program. If you're using and discarding 100MB per second from the LOH, you're only about 21 seconds away from crashing your program. The reason for this is that the LOH is collected, but never compacted. Memory is reclaimed and available for the operating system to give to other programs, but your process's address space is still locked up. 100MB/s * 21s will fill up the 2GB address space available for your process. At that point, you're stuck with an OutOfMemoryException.
Additionally, I hope you're using other measures besides percent of time in garbage collection. Processing 100MB/s, you'll have to get used to a high number there. When that is the case, lower isn't always better. Imagine you have a program that runs at 80% garbage collection and completes in 5 minutes. That's 4 minutes in garbage collection. You add some code to look at each object and break them up or build new ones to get a more-favorable GC profile. It may seem to work — let's say your new number is 75%. But did you really gain anything if that 75% comes from a 6 minute program run and 4.5 minutes in garbage collection, because of the increased code complexity? In other words, don't use percent of time in garbage collection unless you also pair that measure with total processing time. That said, anything over 50% looks suspect to me, so I think you do have some room for improvement here.
My intuition makes me think that the LOH would be faster as management of the LOH is significantly more straightforward i.e. no generations, no scanning and no compaction (objects at or over 85k go in the LOH). Your real enemy with the LOH is that there is no compaction and therefore fragmentation can be an issue, but if you are allocating objects of the same size that are short-lived this should lessen the possibility of fragmentation.
However, intuition is one thing, reality is another. So as with most performance quesitons:
Don't think, measure.
A scheme where you re-use the memory is likely to be a better solution.
The GC does a few things
1. Find all live objects
2. Compact the memory used by live objects
Fewer live objects means that it will be faster to find them. Large objects are allocated from a special heap that is not compacted on all collection so it will be faster.
In theory, fewer large objects allows faster GC. If that affects the performance of the entire application is something you need to measure. I would write the most maintainable code first and see if performance is a problem.
GC effort is not based on the total number of objects, but the number of reachable objects (determines effort per collection) and the rate of allocation (determines number of collections).
The size of short-lived objects shouldn't have much effect on GC effort, assuming the allocation rate in bytes/sec is the same.
The exception would be objects that have finalizers. (Strictly speaking, these aren't short-lived.) Objects that are reachable from objects with finalizers are also very bad. You may need to split some classes and put the finalizable stuff into a member subobject (not a base class), so that only the fields used by the finalizer are part of the finalizable subobject, and the rest of the composite object can be released immediately.
精彩评论