我编写了一个简单的内存分配器,基本上创建了一个已分配的块链,它们使用存储在分配区域之前的元数据struct
中的指针链接在一起。
代码工作正常,我能够分配大小为sz
的块链,然后用我写的另一个函数释放。
问题在于,我注意到,使用vmmap
命令,显然内存由malloc
分配,而没有明确请求它。这是在程序执行的不同时刻拍摄的各种vmmap
的粘贴:
## 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%
我在OS X上,我使用vm_allocate
例程为我的块分配内存。因此,正如预期的那样,VM_ALLOCATE
中的vmmap
部分显示链释放后,部分内存返回初始大小,即8K。我从不在我的代码中调用malloc
。
但显然,MALLOC
部分大小在分配后会增加!它永远不会释放。链条释放后的总尺寸比链条分配前多10MB。
有谁知道为什么会发生这种情况?我不认为vm_allocate
例程调用malloc
,这是没有意义的。在此先感谢您的帮助!
我实际上已经注释掉了我的程序所做的所有分配代码,基本上留下了一个空的main
函数。然后重复我的程序的三个vmmap
检查。结果:
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
区域现在没有按预期增加,没有人正在调用vm_allocate
。但是,正如您所看到的,MALLOC
区域仍在增加!即使没有我的代码。它确实比以前增长更少,即11MB而不是18MB。
这意味着我的代码对它有一些直接的影响,但它可能是什么?也许库函数正在调用malloc
?我在分配代码中使用了一些printf
,我知道像printf
这样的函数调用malloc
,但为什么内存没有被释放?
很抱歉之前没有包括它,如果它是一团糟,我很抱歉,我已经写了大约两个小时,这是我第一次尝试创建自定义分配器。
#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;
}
您可以在代码中看到我使用malloc_printf
。我之前在那里打电话给printf
。 malloc_printf
函数与printf
类似,但无法调用malloc
。
这似乎解决了泄漏问题!我稍后会做更多测试,但是对于我所看到的问题,确实可能是printf
的OS X实现。
答案 0 :(得分:1)
vm_deallocate
函数在指定任务的地址空间中释放虚拟内存区域。该区域从包含地址的虚拟页面的开头开始,并在包含address + size - 1
的虚拟页面的末尾结束。由于这种向虚拟页面边界的舍入,释放的内存量可能大于大小。
我认为引用不会被清除,这就是为什么其他线程仍然可以引用这个地址空间的原因。如果你连续运行上面提到的程序,它可能会导致崩溃,同时还需要清除引用。
如果我错了,请纠正我。