How to make iPhone app that fills in memory quickly
Most likely, what is happening is a tricksy bit of virtual addressing behind your back.
Namely, an application is free to reserve up to the full 4GB of 32-bit address space available to it (less than 4GB, really, because there is fragmentation caused by various system pieces).
When you do malloc(REALLYBIGNUMBER)
, the system uses vm_allocate()
to fulfill the request. The mach memory manager hands you back the addresses, but doesn't actually back it with real memory (kinda like the US economy has tons of $$$ in the market not backed by any real asset).
Physical memory will only be used when you write (or, technically, read) something to the memory. And it will only happen page by page.
So, if you were to walk through the allocated buffer in strides of 4096 (page size) and write one byte, you'd quickly see real memory being consumed.
Can you not just simulate a memory warning in the simulator using the 'Device' menu?
Here is what I do to simulate the use of a large block of memory.
#define MEGA (1024 * 1024)
- (void)stressTestTheApplicationBySimulatingMemoryScarcity {
NSUInteger sizeInMB = 20; // Size in MB. The higher, the more memory will be used here, leaving less for the application
// On iPad: 30 seems to be the upper limit you can ask. YMMV
#if MEMORY_STRESS_TEST_SCARCITY_ENABLED
#warning MEMORY_STRESS_TEST_SCARCITY_ENABLED - THIS SHOULD NOT HAPPEN IN PRODUCTION
#else
return;
#endif
NSLog(@"MEMORY STRESS TEST ENABLED (%dMB)", sizeInMB);
void * unusedMemoryBufferToSimulateMemoryScarcity = NSZoneCalloc(NSDefaultMallocZone(), sizeInMB * MEGA, 1);
if (NULL == unusedMemoryBufferToSimulateMemoryScarcity) {
NSLog(@"MEMORY STRESS TEST FAILED: Was unable to allocate requested memory");
return;
}
dataToRetainToSimulateMemoryScarcity = [[NSData dataWithBytesNoCopy:unusedMemoryBufferToSimulateMemoryScarcity
length:sizeInMB * MEGA
freeWhenDone:YES] retain];
if (dataToRetainToSimulateMemoryScarcity == nil) {
NSLog(@"Failed to retain data to simulate memory scarcity");
}
}
Done this way, the memory allocation is seen by Instruments.
The memset
solution suggested by bbum might have done the trick instead of the dataWithBytesNoCopy: length: freeWhenDone:
The warning and logs left in place help to make sure I do not ship it by error.
If you add some of this code to a project, I suggest you keep them as well (and turn on the Treat warning as error option)..