I have written a simple memory allocator, basically creates a chain of allocated blocks, they are linked together using pointers stored in a metadata struct
before the allocated area.
The code works perfectly, and I am able to allocate chain of blocks of size sz
which are then freed with another function written by me.
The problem is that I noticed, using vmmap
command, that apparently memory is being allocated by malloc
without explicitly requesting it. Here's a paste of various vmmap
, taken at different point of the program execution:
## before first alloc
# this has been taken before any allocation happens in the code.
REGION TYPE VIRTUAL
=========== =======
Kernel Alloc Once 4K
MALLOC 9388K see MALLOC ZONE table below
MALLOC (admin) 24K
STACK GUARD 56.0M
Stack 8192K
VM_ALLOCATE 8K <-- we start with 8K
__DATA 668K
__LINKEDIT 70.2M
__TEXT 5860K
shared memory 4K
=========== =======
TOTAL 149.8M
VIRTUAL ALLOCATION BYTES
MALLOC ZONE SIZE COUNT ALLOCATED % FULL
=========== ======= ========= ========= ======
DefaultMallocZone_0x10ad37000 9216K 363 27K 0%
=======================================================================
## after first alloc
# this is after the chain allocation.
REGION TYPE VIRTUAL
=========== =======
Kernel Alloc Once 4K
MALLOC 18.2M <-- why the hell does malloc() increase?
MALLOC (admin) 24K
STACK GUARD 56.0M
Stack 8192K
VM_ALLOCATE 8200K <-- this is expected, we allocate memory with vm_allocate()
__DATA 668K
__LINKEDIT 70.2M
__TEXT 5860K
shared memory 4K
=========== =======
TOTAL 166.8M
VIRTUAL ALLOCATION BYTES
MALLOC ZONE SIZE COUNT ALLOCATED % FULL
=========== ======= ========= ========= ======
DefaultMallocZone_0x10ad37000 18.0M 364 31K 0%
=======================================================================
## after chain release
REGION TYPE VIRTUAL
=========== =======
Kernel Alloc Once 4K
MALLOC 19.2M <-- malloc increases even more?!?
MALLOC (admin) 24K
STACK GUARD 56.0M
Stack 8192K
VM_ALLOCATE 8K <-- after chain release
__DATA 668K
__LINKEDIT 70.2M
__TEXT 5860K
shared memory 4K
=========== =======
TOTAL 159.8M <-- but why has total size increased?
VIRTUAL ALLOCATION BYTES
MALLOC ZONE SIZE COUNT ALLOCATED % FULL
=========== ======= ========= ========= ======
DefaultMallocZone_0x10ad37000 19.0M 364 31K 0%
I am on OS X and I use the vm_allocate
routine to allocate memory for my blocks. So, as expected, the VM_ALLOCATE
section in vmmap
shows that after the chain release, the section memory returns to initial size, i.e. 8K. I never call malloc
in my code.
But apparently, the MALLOC
section size increases after the allocation! And it never frees. The total size, after the chain release is 10MB more than before the chain allocation.
Has anyone idea of why could this happen? I don't think that the vm_allocate
routine calls malloc
, that wouldn't make sense. Thanks in advance for any help!
I actually commented out all the allocating code that my program did, basically left an empty main
function. Then repeated the three vmmap
checks for my program. Results:
REGION TYPE VIRTUAL
=========== =======
Kernel Alloc Once 4K
MALLOC 9388K see MALLOC ZONE table below
MALLOC (admin) 24K
STACK GUARD 56.0M
Stack 8192K
VM_ALLOCATE 8K
__DATA 668K
__LINKEDIT 70.2M
__TEXT 5860K
shared memory 4K
=========== =======
TOTAL 149.8M
VIRTUAL ALLOCATION BYTES
MALLOC ZONE SIZE COUNT ALLOCATED % FULL
=========== ======= ========= ========= ======
DefaultMallocZone_0x105379000 9216K 363 27K 0%
=========================================================================
REGION TYPE VIRTUAL
=========== =======
Kernel Alloc Once 4K
MALLOC 10.2M see MALLOC ZONE table below
MALLOC (admin) 24K
STACK GUARD 56.0M
Stack 8192K
VM_ALLOCATE 8K
__DATA 668K
__LINKEDIT 70.2M
__TEXT 5860K
shared memory 4K
=========== =======
TOTAL 150.8M
VIRTUAL ALLOCATION BYTES
MALLOC ZONE SIZE COUNT ALLOCATED % FULL
=========== ======= ========= ========= ======
DefaultMallocZone_0x105379000 10.0M 363 27K 0%
=========================================================================
REGION TYPE VIRTUAL
=========== =======
Kernel Alloc Once 4K
MALLOC 11.2M see MALLOC ZONE table below
MALLOC (admin) 24K
STACK GUARD 56.0M
Stack 8192K
VM_ALLOCATE 8K
__DATA 668K
__LINKEDIT 70.2M
__TEXT 5860K
shared memory 4K
=========== =======
TOTAL 151.8M
VIRTUAL ALLOCATION BYTES
MALLOC ZONE SIZE COUNT ALLOCATED % FULL
=========== ======= ========= ========= ======
DefaultMallocZone_0x105379000 11.0M 363 27K 0%
VM_ALLOCATE
region now doesn't increase, as expected, no one is calling vm_allocate
. But, as you can see, the MALLOC
region still increases! Even without my code. It does grow less than before, i.e. 11MB instead of 18MB.
This means that my code has some direct influence on it, but what could it be? Maybe library functions are calling malloc
? I use some printf
in my allocating code, and I know functions like printf
call malloc
, but why then the is memory not released?
Sorry for not including it before, and sorry if it is a total mess, I have written this in around two hours and it's my first attempt at creating a custom allocator.
#include <mach/mach.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc/malloc.h>
#define BLOCK_NO 2048
typedef struct mem_block {
struct mem_block *next;
unsigned int sz;
unsigned int free:1;
} mem_block_t;
void *alloc_block(vm_size_t size)
{
void *block_addr=NULL;
mem_block_t metadata;
vm_address_t *start_addr=0;
vm_allocate(mach_task_self_, (vm_address_t*)&start_addr, size, 1);
block_addr=(start_addr);
metadata.next=(void*)NULL;
metadata.sz=(unsigned int)size;
metadata.free=0x0;
memcpy(block_addr, (mem_block_t*)&metadata, sizeof(mem_block_t));
return block_addr+sizeof(mem_block_t);
}
void dealloc_block(void *block_addr)
{
unsigned int sz=0;
vm_address_t start_addr = (vm_address_t)block_addr-sizeof(mem_block_t);
memcpy(&sz, (void*)start_addr+sizeof(mem_block_t*), sizeof(sz));
vm_deallocate(mach_task_self_, start_addr, sz);
}
void *alloc_block_chain(unsigned int blocks, vm_size_t size)
{
void *head=NULL, *old_block=NULL, *curr=NULL;
head = alloc_block(size);
old_block = head;
for (int i=0; i<blocks-1; i++) {
curr = alloc_block(size);
((mem_block_t*)old_block)->next=curr;
old_block=curr;
}
return head;
}
void dealloc_block_chain(void *block_addr_start)
{
int cnt=0;
void *curr=NULL, *old_block=NULL;
curr=block_addr_start;
while(1) {
if (old_block) {
dealloc_block(old_block);
malloc_printf("dealloc'd block #%d: %p\n", cnt, old_block);
cnt++;
}
if (!((mem_block_t*)curr)->next) {
dealloc_block(curr);
malloc_printf("dealloc'd final block: %p\n", curr);
break;
} else {
old_block = curr;
curr=((mem_block_t*)curr)->next;
}
}
}
int main(int argc, const char * argv[]) {
system("read -n 1 -s -p \"Press any key to continue...\";echo");
void *start = alloc_block_chain(BLOCK_NO, PAGE_SIZE);
void *curr=start;
for (int i=0; i<BLOCK_NO; i++) {
malloc_printf("block #%d: %p\n", i, curr);
curr = ((mem_block_t*)curr)->next;
}
system("read -n 1 -s -p \"Press any key to continue...\";echo");
dealloc_block_chain(start);
system("read -n 1 -s -p \"Press any key to continue...\";echo");
return 0;
}
You can see I use malloc_printf
in the code. I previously called printf
there. The malloc_printf
function is similar to printf
but avoids calling malloc
.
This seems to fix the leak! I will do more testing later, but for what I have seen the problem could indeed be OS X implementation of printf
.
Allow Windows 10 to Allocate More RAMSelect Advanced system settings > Settings. Under the Visual Effects tab, there are four options. Select the Adjust for best performance option. After you do this, click Apply.
Operator new can fail In the above example, if new fails to allocate memory, it will return a null pointer instead of the address of the allocated memory. Note that if you then attempt indirection through this pointer, undefined behavior will result (most likely, your program will crash).
The free() function is used to free the memory which is allocated previously using malloc() or calloc(). Syntax: free(mem_ptr);
The vm_deallocate
function deallocates a region of virtual memory in the specified task's address space. The region starts at the beginning of the virtual page containing address and ends at the end of the virtual page containing address + size - 1
. Because of this rounding to virtual page boundaries, the amount of memory deallocated may be greater than size.
I think references wont be cleared and this is why other threads can still reference to this address space.if you run the mentioned program continuously it may lead to crash as well as the reference should also needs to be cleared.
Correct me if I am wrong.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With