0

I have written my own my_malloc() function that manages its own physical memory. In my application I want to be able use both the libc malloc() as well as my own my_malloc() function. So I somehow need to partition the virtual address space, malloc should always assign a virtual address only if its from its dedicated pool, same thing with my_malloc(). I cannot limit heap size, I just need to guarantee that malloc() and my_malloc() never return the same/overlapping virtual addresses.

thanks!

Matt
  • 22,721
  • 17
  • 71
  • 112
hlitz
  • 635
  • 6
  • 24

4 Answers4

1

One answer is to make your my_malloc use memory allocated by malloc. Using big enough blocks would mostly acheive that; then within each block your version will maintain its own structures and allocate parts of it to callers.

It gets tricky because you can't rely on extending the entire available space for your version, as you can when you get memory from sbrk or similar. So your version would have to maintain several blocks.

Edmund
  • 10,533
  • 3
  • 39
  • 57
1

One possibility would be to have my_malloc() call malloc() at startup to pre-allocate a large pool of memory, then apportion that memory to its callers and manage it accordingly. However, a full implementation would need to handle garbage collection and defragmentation.

Another possibility would be to have my_malloc() call malloc() each time it needs to allocate memory and simply handle whatever "bookkeeping" aspects you're interested in, such as number of blocks allocated, number of blocks freed, largest outstanding block, total allocated memory, etc. This is by far the safer and more efficient mechanism, as you're passing all of the "hard" operations to malloc().

Adam Liss
  • 47,594
  • 12
  • 108
  • 150
1

Reserve a large block of virtual address space, and have that be the pool from which my_malloc() allocates. Once you have reserved a large contiguous region of memory from the OS, then subsequent calls to malloc() have to come from elsewhere.

For example, on Windows, you can use VirtualAlloc() to reserve a 256mb block of space. The memory won't actually be allocated until you "commit" it with a subsequent call, but it will reserve an address range (such as 0x4000000-0x5000000) which subsequent malloc() will not use. Then your my_malloc() can commit blocks out of this reserved range as requested, and subdivide them by whatever allocation scheme you've written.

I'm told the equivalent Linux call is mmap(). (edit: I previously said "kmalloc or vmalloc, depending on whether you need the memory to be physically contiguous or not," but those are kernel-level functions.)

We use this mechanism in our app to redirect all allocations of a certain size into our own custom pooled-block allocator for speed and efficiency. Among other things, it lets us reserve virtual pages in certain specific sizes that are more efficient for the CPU to handle.

Community
  • 1
  • 1
Crashworks
  • 40,496
  • 12
  • 101
  • 170
  • `kmalloc` and such are kernelspace functions; they have nothing to do with applications. The function OP wants is `mmap`. Or, OP could just use the real `malloc` to get the large block for `my_malloc` to allocate from. – R.. GitHub STOP HELPING ICE May 05 '12 at 01:22
  • @R.. I guess I'm too used to writing embedded kernel-level code! I've fixed the answer. – Crashworks May 05 '12 at 01:32
0

If you add an mmap(2) call near the start of the program, you can allocate as much memory as you need with whatever addresses you need (see the hint, that's usually left NULL for the OS to determine) immediately; that will prevent malloc(3), or any other memory allocation routines, from getting those particular pages.

Don't worry about the memory usage; since modern systems are quite happy to overcommit, you'll only use a few hundred kilobytes more kernel space to handle page tables. Not too bad.

sarnold
  • 102,305
  • 22
  • 181
  • 238
  • Overcommit is NOT a good thing here. The whole purpose of what OP is doing is to make sure the memory is available when it's needed later. Better make sure overcommit is disabled (`echo "2" > /proc/sys/vm/overcommit_memory`) – R.. GitHub STOP HELPING ICE May 05 '12 at 01:23
  • @R..: Oh? I had assumed he just wanted different virtual memory address ranges for _his_ memory and _malloc_'s memory. You might be right -- if he is doing it to defeat overcommit, then definitely steps must be taken. Just `overcommit_memory` alone isn't sufficient; `overcommit_ratio` must also be modified. – sarnold May 05 '12 at 22:13
  • `overcommit_memory` alone is sufficient; the default value of `overcommit_ratio` (50%), and in fact anything bounded sufficiently away from near-100%, is safe to avoid OOM. – R.. GitHub STOP HELPING ICE May 05 '12 at 22:41
  • @R..: thanks! I had been working under the assumption that something much closer to `0` would be necessary. – sarnold May 05 '12 at 22:43
  • 1
    50% means the kernel will never allow the commit charge (basically, amount of allocated memory that has the potential to store data that's not backed on disk) to exceed 50% of the total physical memory (including swap). Keeping in mind that system performance will be very bad if you don't also have room in memory for a decent number of shared pages of code (not counted in commit charge) and filesystem cache/buffer, 50% is probably good as long as you don't have too much swap (swap size < 50-100% of ram size). With too much swap, things will go to hell long before you OOM anyway... – R.. GitHub STOP HELPING ICE May 05 '12 at 22:53
  • In principle, though, having the ratio near 100% should be okay. I'd just be worried that the kernel might make small accounting errors that allow some OOM corner cases to slip through, but if you want to run without any swap (e.g. robust realtime systems) and find yourself short on memory, putting the ratio up to 80% or so is probably safe, but may impact performance badly if there's not enough room left for optimal caching (which may in turn destroy realtime properties). – R.. GitHub STOP HELPING ICE May 05 '12 at 22:55