Any way to catch memory fragmentation on windows?

Started by
5 comments, last by 3DModelerMan 11 years, 6 months ago
Is there any way to turn of the virtual memory system in debug builds on win32? I want to make sure my code doesn't cause memory fragmentation.
Advertisement
What, you mean write directly to physical memory? No, operating systems will not let you do that. Their whole process architecture is based on memory being virtualized.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Oh. Is there any way to track memory fragmentation on Windows then? Or maybe Linux?
The virtual memory system uses pages as the lowest granularity of memory allocation for a program, which means that at the smallest fragments of memory are page-size. Pages are pretty big (4KB+), and memory is more or less random access, so there is very little performance penalty from memory being fragmented.

Edit: unless you mean you want to see if your code is fragmenting your own memory, in which case the virtual memory system has no effect, because as far as your program is concerned it just has one giant block of contiguous memory. To see if you have internal fragmentation, you'd have to use your own memory management system to keep track of what memory is free and what memory is taken, and at some time print / save / whatever a graphical representation of the memory. You can then see how bad the fragmentation gets.
Virtual memory and memory fragmentation (address space fragmentation, all your application can see) have nothing to do with each other. If you see problems with memory fragmentation, you need to turn a different knob. Either enable the low fragmentation heap or better yet avoid fragmentation by not using unhealthy allocation patterns.
For example, [font=courier new,courier,monospace]std::vector[/font] uses a very unhealthy allocation pattern if you keep pushing back data without reserving. It will first allocate a larger block, copy data, and then free the smaller block. STB Vorbis (if I remember correctly, might be the reference Vorbis implementation, too) uses a similar pattern to determine the length of a soundfile.

Physical memory is fragmented into 4k chunks (some of it possibly in 1M chunks with large page support) either way, there is nothing you can do about it, and no reason why you should care. It does not affect you or the system in any way, this is just as it's supposed to be.
Are you actually quite sure that memory fragmentation is a problem for you, are are you just pre-emptively anticipating it without having done any tests yet? This kind of low-level problem is something that you normally do not have to deal with in a program. It looks an awful lot like you're going down a micro-optimization route.

If you still insist, then you can use the Heap* API calls on Windows (HeapAlloc, HeapFree, etc), and every now and then make a call to HeapCompact, which will clean things up for you: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366598%28v=vs.85%29.aspx

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.


Oh. Is there any way to track memory fragmentation on Windows then? Or maybe Linux?
Assuming you're concerned about fragmentation within your own address space, and not physical fragmentation:
Every game engine I've used has had an optional "memory tracking mode", which is usually #ifdef'ed out. This mode adds extra code to every new/delete/malloc/free call to keep a log of every allocation.
You can use this log for many purposes, like seeing which lines memory leaks came from, or how much memory different game systems are using, or the order in which things are created.
Usually the engine will also provide some external tools to inspect these logs, such as visualizing all allocations as pixels in a 2D image. Large allocations might take up many rows of pixels, while small allocations might just be dots. If you see lots of tiny empty spaces between allocations, that's fragmentation.

For an example of what this typically looks like, check out Elephant and Goldfish.

On PC, using default allocators, this really isn't much of a problem. New/Malloc simply aren't going to fail due to fragmentation... unless maybe you've got 4GiB of data allocated at once... PC has a huge address space to play with, so it's ok to be naive about efficient memory usage.

Memory fragmentation is a much bigger issue on consoles, where maybe you've only got 256MiB of RAM! On these systems, it's easy to end up in a situation where you've got 200MiB allocated, with 56MiB free, however that 56MIB is actually spread over 50 different ~1MiB blocks, so asking for 10MiB will fail.

My advice to avoid fragmentation would be to unlearn the idea that you can just grab/release memory with new/delete whenever you feel like it, and instead be much more structured in how you allocate things. E.g. if you know a level has a maximum of 100 monsters alive at once, then at the start of the level, make a pool containing 100 monsters - then you don't have to allocate new ones whenever they spawn using new/delete, you can get them from the pool.
In my engine, I treat new/malloc as a "global variable", which means their use is banned for being evil.

Another thing you can do is stop using pointers to refer to objects. If you use other identifiers, then you can support relocating objects.
e.g. if you had a collection of up to 256 Objects, and you wanted to be able to move those objects to support de-fragmenting memory, you could use a table like:
struct Table
{
Object* addresses[256];
Object* GetObject( int id ) { return addresses[id]; }
}
which means you can reallocate an object somewhere else, and just update the table to point to the new allocation. Anyone "pointing" to the object via an id doesn't have to know that it's moved. DotNET and Java do this behind the scenes, thanks to not using pointers.
e.g. if when transitioning from level1 to level2, you know that 50% of the currently loaded assets are going to be used by the next level, you can free the unneeded level1 assets, then you can move the remaining ones to ensure there's no wasted space between them, and then load the new level2 assets knowing there's no fragmentation.
Thanks for the advice. And the reason I was wondering is because I wanted to make sure that when I run my code on consoles that I don't end up fragmenting memory all over the place.

This topic is closed to new replies.

Advertisement