Thursday, 30 January 2014

Allocating Large Memory Blocks using Malloc for Mobile apps

Allocating Large Memory Blocks using Malloc
For large memory allocations, where large is anything more than a few virtual memory pages, malloc
automatically uses the vm_allocate routine to obtain the requested memory. The vm_allocate routine
assigns an address range to the new block in the logical address space of the current process, but it does not assign any physical memory to those pages right away. Instead, the kernel does the following:
1. It maps a range of memory in the virtual address space of this process by creating a map entry; the map entry is a simple structure that defines the starting and ending addresses of the region.
2. The range of memory is backed by the default pager.
3. The kernel creates and initializes a VM object, associating it with the map entry.
At this point there are no pages resident in physical memory and no pages in the backing store. Everything is mapped virtually within the system. When your code accesses part of the memory block, by reading or writing to a specific address in it, a fault occurs because that address has not been mapped to physical memory. In OS X, the kernel also recognizes that the VM object has no backing store for the page on which this address occurs.
The kernel then performs the following steps for each page fault:
1. It acquires a page from the free list and fills it with zeroes.
2. It inserts a reference to this page in the VM object’s list of resident pages.
3. It maps the virtual page to the physical page by filling in a data structure called the pmap. The pmap contains the page table used by the processor (or by a separate memory management unit) to map a given virtual address to the actual hardware address.
The granularity of large memory blocks is equal to the size of a virtual memory page, or 4096 bytes. In other words, any large memory allocations that are not a multiple of 4096 are rounded up to this multiple automatically. Thus, if you are allocating large memory buffers, you should make your buffer a multiple of this size to avoid wasting memory.
Note: Large memory allocations are guaranteed to be page-aligned.
For large allocations, you may also find that it makes sense to allocate virtual memory directly using
vm_allocate, rather than using malloc. The example in Listing 2 shows how to use the vm_allocate
function.



Listing 2 Allocating memory with vm_allocate
void* AllocateVirtualMemory(size_t size)
{
char* data;
kern_return_t err;
// In debug builds, check that we have
// correct VM page alignment
check(size != 0);
check((size % 4096) == 0);
// Allocate directly from VM
err = vm_allocate( (vm_map_t) mach_task_self(),
(vm_address_t*) &data,
size,
VM_FLAGS_ANYWHERE);
// Check errors
check(err == KERN_SUCCESS);
if(err != KERN_SUCCESS)
{
data = NULL;
}
return data;
}

Allocating Memory in Batches
If your code allocates multiple, identically-sized memory blocks, you can use the malloc_zone_batch_malloc function to allocate those blocks all at once. This function offers better performance than a series of calls to malloc to allocate the same memory. Performance is best when the individual block size is relatively small—less than 4K in size. The function does its best to allocate all of the requested memory but may return less than was requested. When using this function, check the return values carefully to see how many blocks were actually allocated.

Batch allocation of memory blocks is supported in OS X version 10.3 and later and in iOS. For information, see the /usr/include/malloc/malloc.h header file.
Allocating Shared Memory Shared memory is memory that can be written to or read from by two or more processes. Shared memory can be inherited from a parent process, created by a shared memory server, or explicitly created by an application for export to other applications. Uses for shared memory include the following:
● Sharing large resources such as icons or sounds
● Fast communication between one or more processes
Shared memory is fragile and is generally not recommended when other, more reliable alternatives are available.
If one program corrupts a section of shared memory, any programs that also use that memory share the corrupted data. The functions used to create and manage shared memory regions are in the
/usr/include/sys/shm.h header file.

Using Malloc Memory Zones

All memory blocks are allocated within a malloc zone (also referred to as a malloc heap). A zone is a variable-size range of virtual memory from which the memory system can allocate blocks. A zone has its own free list and pool of memory pages, and memory allocated within the zone remains on that set of pages. Zones are useful in situations where you need to create blocks of memory with similar access patterns or lifetimes. You can allocate many objects or blocks of memory in a zone and then destroy the zone to free them all, rather than releasing each block individually. In theory, using a zone in this way can minimize wasted space and reduce paging activity. In reality, the overhead of zones often eliminates the performance advantages associated with the zone.
Note: The term zone is synonymous with the terms heap, pool, and arena in terms of memory
allocation using the malloc routines.
By default, allocations made using the malloc function occur within the default malloc zone, which is created when malloc is first called by your application. Although it is generally not recommended, you can create additional zones if measurements show there to be potential performance gains in your code. For example, if the effect of releasing a large number of temporary (and isolated) objects is slowing down your application, you could allocate them in a zone instead and simply deallocate the zone.




If you are create objects (or allocate memory blocks) in a custom malloc zone, you can simply free the entire zone when you are done with it, instead of releasing the zone-allocated objects or memory blocks individually.
When doing so, be sure your application data structures do not hold references to the memory in the custom zone. Attempting to access memory in a deallocated zone will cause a memory fault and crash your application.

Warning: You should never deallocate the default zone for your application.

At the malloc library level, support for zones is defined in /usr/include/malloc/malloc.h. Use the
malloc_create_zone function to create a custom malloc zone or the malloc_default_zone function to
get the default zone for your application. To allocate memory in a particular zone, use the malloc_zone_malloc , malloc_zone_calloc , malloc_zone_valloc , or malloc_zone_realloc functions. To release the memory in a custom zone, call malloc_destroy_zone.

No comments:

Post a Comment