Re: Is my program leaking?
Re: Is my program leaking?
- Subject: Re: Is my program leaking?
- From: Marc Van Olmen <email@hidden>
- Date: Mon, 19 Sep 2005 09:13:51 -0400
hi,
I figured out that it is "leaking" in some code I used for a long time,
it is a code that allocates a buffer that is circular by using a sort
of Virtual memory technique...
I picked this code up from the internet and it seems that causes the
leak... I'm guessing that the vm_deallocate is not releasing all the
memory.
The current leak doesn't seem to be traceable by mallocdebug because it
isn't using any of those calls... I was using that tool before...
Here the code:
/
/-----------------------------------------------------------------------
-----------------
// AllocateVirtualBuffer
/
/-----------------------------------------------------------------------
-----------------
static void * AllocateVirtualBuffer(OS_MemorySize pBufferLength)
{
kern_return_t error;
vm_address_t originalAddress = NULL;
vm_address_t realAddress = NULL;
mach_port_t memoryEntry;
vm_size_t memoryEntryLength;
vm_address_t virtualAddress = NULL;
OS_Int32 errorCount;
// We want to find where we can get 2 * fBufferLength bytes of
contiguous address space.
// So let's just allocate that space, remember its address, and
deallocate it.
// (This doesn't actually have to touch all of that memory so it's
not terribly expensive.)
error = vm_allocate(mach_task_self(), &originalAddress, 2 *
pBufferLength, TRUE);
if (error) {
#ifdef mkDebug
OS_Debug_Break("vm_allocate initial chunk", error);
#endif
return NULL;
}
error = vm_deallocate(mach_task_self(), originalAddress, 2 *
pBufferLength);
if (error) {
#ifdef mkDebug
OS_Debug_Break("vm_deallocate initial chunk", error);
#endif
return NULL;
}
// Then allocate a "real" block of memory at the same address, but
with the normal pBufferLength.
realAddress = originalAddress;
error = vm_allocate(mach_task_self(), &realAddress, pBufferLength,
FALSE);
if (error) {
#ifdef mkDebug
OS_Debug_Break("vm_allocate real chunk", error);
#endif
return NULL;
}
if (realAddress != originalAddress) {
#ifdef mkDebug
OS_Debug_Log("allocateVirtualBuffer: vm_allocate 2nd time
didn't return same address (%p vs %p)\n", originalAddress,
realAddress);
#endif
goto errorReturn;
}
// Then make a memory entry for the area we just allocated.
memoryEntryLength = pBufferLength;
error = mach_make_memory_entry(mach_task_self(),
&memoryEntryLength, realAddress, VM_PROT_READ | VM_PROT_WRITE,
&memoryEntry, NULL);
if (error) {
#ifdef mkDebug
OS_Debug_Break("mach_make_memory_entry", error);
#endif
goto errorReturn;
}
if (!memoryEntry) {
#ifdef mkDebug
OS_Debug_Log("mach_make_memory_entry: returned memoryEntry of
NULL\n");
#endif
goto errorReturn;
}
if (memoryEntryLength != pBufferLength) {
#ifdef mkDebug
OS_Debug_Log("mach_make_memory_entry: size changed (from %0x to
%0x)\n", pBufferLength, memoryEntryLength);
#endif
goto errorReturn;
}
// And map the area immediately after the first block, with length
pBufferLength, to that memory entry.
virtualAddress = realAddress + pBufferLength;
errorCount = 0;
while (errorCount <10) {
error = vm_map(mach_task_self(), &virtualAddress, pBufferLength, 0,
FALSE, memoryEntry, 0, FALSE, VM_PROT_READ | VM_PROT_WRITE,
VM_PROT_READ | VM_PROT_WRITE, VM_INHERIT_DEFAULT);
if (error) {
#ifdef mkDebug
OS_Debug_Break("vm_map", error);
#endif
// TODO Retry from the beginning, instead of failing completely.
There is a tiny (but > 0) probability that someone
// will allocate this space out from under us.
virtualAddress = NULL;
goto errorReturn;
} else {
break;
}
errorCount++;
}
if (virtualAddress != realAddress + pBufferLength) {
#ifdef mkDebug
OS_Debug_Log("vm_map: didn't return correct address (%p vs
%p)\n", realAddress + pBufferLength, virtualAddress);
#endif
goto errorReturn;
}
// Success!
return (void *)realAddress;
#ifdef mkDebug
// Here's a little test...
*(char *)realAddress = '?';
if (*(char *)virtualAddress != '?')
OS_Debug_Log("VirtualRingBuffer: Test 1: vm magic failed\n");
*(char *)(virtualAddress + 1) = '!';
if (*(char *)(realAddress + 1) != '!')
OS_Debug_Log("VirtualRingBuffer: Test 2: vm magic failed\n");
#endif
errorReturn:
if (realAddress)
vm_deallocate(mach_task_self(), realAddress, pBufferLength);
if (virtualAddress)
vm_deallocate(mach_task_self(), virtualAddress, pBufferLength);
return NULL;
}
/
/-----------------------------------------------------------------------
-----------------
// FreeVirtualBuffer
/
/-----------------------------------------------------------------------
-----------------
void FreeVirtualBuffer(void *fBuffer, UInt32 pBufferLength)
{
kern_return_t error;
// We can conveniently deallocate both the vm_allocated memory and
// the vm_mapped region at the same time.
error = vm_deallocate(mach_task_self(), (vm_address_t)fBuffer,
pBufferLength * 2);
if (error) {
#ifdef mkDebug
OS_Debug_Break("vm_deallocate in dealloc", error);
#endif
}
}
On Sep 19, 2005, at 2:12 AM, plumber wrote:
Should I be worried?
Is my application leaking memory?
How can I trace where the leak is happening?
take a look here /Developer/Applications/Performance Tools/
Best Regards
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden