Force garbage collection of arrays, C#

2019-01-11 23:09发布

I have a problem where a couple 3 dimensional arrays allocate a huge amount of memory and the program sometimes needs to replace them with bigger/smaller ones and throws an OutOfMemoryException.

Example: there are 5 allocated 96MB arrays (200x200x200, 12 bytes of data in each entry) and the program needs to replace them with 210x210x210 (111MB). It does it in a manner similar to this:

array1 = new Vector3[210,210,210];

Where array1-array5 are the same fields used previously. This should set the old arrays as candidates for garbage collection but seemingly the GC does not act quickly enough and leaves the old arrays allocated before allocating the new ones - which causes the OOM - whereas if they where freed before the new allocations the space should be enough.

What I'm looking for is a way to do something like this:

GC.Collect(array1) // this would set the reference to null and free the memory
array1 = new Vector3[210,210,210];

I'm not sure if a full garbage collecion would be a good idea since that code may (in some situations) need to be executed fairly often.

Is there a proper way of doing this?

10条回答
成全新的幸福
2楼-- · 2019-01-11 23:57

They might not be getting collected because they're being referenced somewhere you're not expecting.

As a test, try changing your references to WeakReferences instead and see if that resolves your OOM problem. If it doesn't then you're referencing them somewhere else.

查看更多
三岁会撩人
3楼-- · 2019-01-11 23:58

Part of the problem may be that you're allocating a multidimensional array, which is represented as a single contiguous block of memory on the large object heap (more details here). This can block other allocations as there isn't a free contiguous block to use, even if there is still some free space somewhere, hence the OOM.

Try allocating it as a jagged array - Vector3[210][210][210] - which spreads the arrays around memory rather than as a single block, and see if that improves matters

查看更多
4楼-- · 2019-01-11 23:59

John, Creating objects > 85000 bytes will make the object end up in the large object heap. The large object heap is never compacted, instead the free space is reused again. This means that if you are allocating larger arrays every time, you can end up in situations where LOH is fragmented, hence the OOM.

you can verify this is the case by breaking with the debugger at the point of OOM and getting a dump, submitting this dump to MS through a connect bug (http://connect.microsoft.com) would be a great start.

What I can assure you is that the GC will do the right thing trying to satisfy you allocation request, this includes kicking off a GC to clean the old garbage to satisfy the new allocation requests.

I don't know what is the policy of sharing out memory dumps on Stackoverflow, but I would be happy to take a look to understand your problem more.

查看更多
Bombasti
5楼-- · 2019-01-12 00:02

Seems you've run into LOH (Large object heap) fragmentation issue.

Large Object Heap

CLR Inside Out Large Object Heap Uncovered

You can check to see if you're having loh fragmentation issues using SOS

Check this question for an example of how to use SOS to inspect the loh.

查看更多
登录 后发表回答