Memory fragmentation in unmanaged memory

This is regarding unmanaged memory access architecture in Unity 6 preview, n beyond. The way I understand is, at least as of Unity 6 preview, it provides access to unmanaged memory via the C# scripting API, which in turn use the Unity C/C++ core engine to directly access unmanaged memory. And in near term, when Unity migrates to .NET CoreCLR, this unmanaged memory access would be directly provided by the .NET CoreCLR without an intermediate C/C++ interface.

Now, as far as I know, unmanaged memory access still suffers from the same issues that were resolved by GC (which is why that part is called managed memory). One of the core issues I’m interested in is memory fragmentation in the unmanaged memory. Even the latest C++ 23 version hasn’t exactly “solved” this memory fragmentation issue, but has some workarounds like smart pointers. So, I’m assuming that same logic applies to Unity 6 preview’s current architecture since it’s using Unity C/C++ core engine - its either

  1. internally employing workarounds (e.g., smart pointers or some custom implementation) - which, at least Unity documentation doesn’t detail at all, n hence seems less likely, or
  2. there’s no workaround implemented in current Unity architecture - just unrestricted raw access to unmanaged memory, thereby eventually leading to fragmentation for games running long - this seems more likely.

Either way, this issue effects all types of unmanaged memory access - the entire DOTS/ECS system, native n unsafe types from Unity Collections, n so on. The Unreal Engine uses .NET Visual C++, n handles fragmentation issue by creating its own custom GC, thereby effectively making the unmanaged memory access a “managed memory access”. And .NET CoreCLR documentation doesn’t mention anything about memory fragmentation issues in unmanaged memory access - so I’m assuming they don’t yet have any workarounds for handling this issue.

So my curiosity/question is

What are Unity’s plans for dealing with memory fragmentation issues for unmanaged memory, with its current C/C++ core engine architecture, n post-migration to .NET CoreCLR ? I would love to hear from somebody in Unity team about plans on this issue.

1 Like

Every programmer explicitly allocating unmanaged memory puts himself in position of the technically responsible party here. So, the same as in case of C++, issues of memory fragmentation etc. are as in programmer hands as everywhere else.

Unity.Collections

When using UnsafeUtility.Malloc or any other allocation method from the Unity.Collections namespace then this API addresses fragmentation issue with Temp and TempJob allocators by imposing allocation lifetime (buffers are wiped clean regularly so fragmentation is non-issue). Persistent allocator puts responsibility back in your hands.


Correct me if I’m wrong but I don’t think smart pointers (ref counting?) and GC help with fragmentation in any way - but with memory leaks, different issue entirely. If one uses standard RAII-like patterns in Unity then leaks won’t happen pretty much.

Memory fragmentation is usually more an issue on the OS level as it’s responsible for managing the actual physical memory. The memory your application “sees” is virtual memory and each application has it’s own virtual address space. Memory can be mapped to any unused space, though the OS is only “handing out” memory in “pages”. Of course when you need large continuous memory, it needs to be continuous. When you have a memory manager in between it usually caches old currently unused pages in case they are needed again because allocating from the OS is rather slow. The more layers you may have in between the worse or at least unpredictable it can get. However unless you constantly allocating / reallocating a multi GB buffer and is always ever so slightly larger that the previous, this shouldn’t really be a big issue.

Memory fragmentation is only really an issue when you need a lot of really large buffers and keep them over a longer period and if you replace them, it would be always a larger buffer. Unity uses different managers and Allocators for the NativeArray and you should simply choose the one that fits your usecase best.

@andrew-lukasik: yes, that was a miss on my part. I recently educated myself on this stuff, n missed this :slight_smile: - thanks for pointing that out !! Native memory allocators indeed address part of this issue. Fragmentation issues occur in all kinds of memory access - managed and unmanaged. The managed memory platforms like .NET CoreCLR handle it via a two-fold solution - (1) trackable two-component allocator-collector model, and (2) post-collection compaction. Compaction is available only to very limited to none extent for larger allocations. The native memory allocators for unmanaged memory in Unity probably address (1) here, limiting to internal fragmentation only at least for temporary allocators. Though there’s no current workaround for addressing (2) in Unity - the compaction aspect. So do the smart pointers on C++ platforms. At best, they provide trackable allocator-collector model, just like native memory allocator solution in Unity. The GC, more specifically, handles the “collector” part of this whole model. Persistent, like you correctly pointed out, could still create an issue. Unreal handles this by offering its own compaction algorithms, in limited manner, that the application can call. In fact, even Unity has this for managed memory. So, I thought Unity would also at least be aware of it, n might have something its roadmaps for dealing with this. So far, no perfect solution exists that covers most use case scenarios.

If someone from Unity team is reading this blog, I would love to hear from them too about any plans on this.

@Bunny83: That’s really not correct. Fragmentation has been an issue at application level since forever (please see my response above for @andrew-lukasik). You’re right about native memory allocators though - I’d missed that important concept before due to oversight. It indeed addresses an important part of the fragmentation aspect - the trackable allocator-collector model via most of the temporary allocators. The persistent one could still introduce fragmentation for long session game matches, unless some form of compaction is available. This is available on Unreal Engine, as the custom implemented GC (which effectively makes Visual C++ on Unreal a “managed” access rather than “unmanaged”) does provide compaction/defragmentation to some extent. Compaction/defragmentation of some kind is usually an important backup, even for large allocations. The timing of it would still need to be adjusted at the application level, so it doesn’t eat away resources during critical gameplay times. But so far, no perfect solution exists anyway for any platform - even .NET CoreCLR handles this only to an extent for larger allocations (e.g. Large Heap Object allocations) - probably limited to no compaction. So I don’t have much hopes from .NET CoreCLR (at least the current version) even after Unity migrates to it completely.