Creating autoreleased object inside GLKViewController run loop causes malloc error - objective-c

I'm currently using GLKit to do some OpenGL drawing. I created a normal UIViewController and then added a GLKViewController subclass inside a container to do my drawing. While everything runs fine initially, if I let my program run for a period of time (perhaps 15-30 minutes), eventually it crashes and gives me the following error.
malloc: *** mmap(size=2097152) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
So I turned on the malloc_error_break breakpoint, and the stack trace points to the following code.
-(NSArray*)meshes:(NSArray *)meshes sortedFromFrontToBack:(BOOL)sortedFromFrontToBack
{
NSMutableArray *sortedMeshes = meshes.mutableCopy;
[sortedMeshes sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
DSNode *mesh1 = obj1;
DSNode *mesh2 = obj2;
GLKVector3 depth1 = isnan(mesh1.boundingSphere.radius) ? mesh1.transformationState.position : mesh1.boundingSphere.center;
GLKVector3 depth2 = isnan(mesh2.boundingSphere.radius) ? mesh2.transformationState.position : mesh2.boundingSphere.center;
GLKMatrix4 mesh1ToCameraSpace = [mesh1 nodeToOtherNodeTransform:self];
GLKMatrix4 mesh2ToCameraSpace = [mesh2 nodeToOtherNodeTransform:self];
GLKVector3 depth1InCameraSpace = GLKMatrix4MultiplyVector3WithTranslation(mesh1ToCameraSpace, depth1);
GLKVector3 depth2InCameraSpace = GLKMatrix4MultiplyVector3WithTranslation(mesh2ToCameraSpace, depth2);
NSNumber *n1 = [NSNumber numberWithFloat:depth1InCameraSpace.z];
NSNumber *n2 = [NSNumber numberWithFloat:depth2InCameraSpace.z]; /* Breakpoint triggered here */
if(sortedFromFrontToBack)
{
return [n2 compare:n1];
}
return [n1 compare:n2];
}];
return sortedMeshes;
}
As I commented, the [NSNumber numberWithFloat:] call throws the malloc error. This method gets called once each frame from my GLKViewController's drawInRect method. Essentially, I have a class which keeps track of my cameras and the meshes which are going to be drawn by OpenGL, and it sorts them in camera space from either front to back for opaque meshes or back to front for transparent before drawing them.
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(self.clearColor.r, self.clearColor.g, self.clearColor.b, self.clearColor.a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
DSDirector *director = [DSDirector sharedDirector];
for(DSMesh *mesh in director.opaqueMeshes)
{
[mesh draw];
}
/* The director class keeps track of my scene's cameras and meshes and calls the above method to return the scene's transparent meshes properly sorted */
for(DSMesh *mesh in director.transparentMeshes)
{
[mesh draw];
}
}
From what I've read, the autorelease pool should drain at the end of each run loop, so I wouldn't think that creating a bunch of autoreleased objects every frame is an issue, they should all get flushed each frame. I've profiled my program and checked for any leaks and can't find any, and I'm using ARC as well, which should minimize the risk. When I profile it, the live bytes total never budges, although the overall bytes rises quite quickly, and no leaks are found. In addition, didReceiveMemoryWarning never fires. I'm stumped.

Something smells wrong about the NSNumber creation being the cause of your malloc error. Testing with Instruments might help find the real culprit.
However, you're doing two things you don't need to, so there's some chance that eliminating them might help with your problem.
First, you don't need to wrap floats in an NSNumber to compare them. The basic comparison and mathematical operators work just fine, and don't require extra time or memory for object creation:
if (depth1InCameraSpace.z < depth2InCameraSpace.z)
return NSOrderedAscending;
else if (depth1InCameraSpace.z > depth2InCameraSpace.z)
return NSOrderedDescending;
else
return NSOrderedSame;
Second, the Tile-Based Deferred Rendering strategy implemented by the GPU hardware on iOS devices does its own hidden surface removal optimizations -- sorting opaque geometry front to back is redundant, so all it does is waste CPU time. (There's a decent explanation of this is in the OpenGL ES Hardware Platform Guide for iOS.) You should still sort translucent geometry back to front (and draw it after opaque geometry) for proper blending, though.

So, I think I've figured out what was going on. At some prior point I'd enabled NSZombies and then forgot about it, and so all of my objects that I expected to be deallocated were actually still hanging around. When profiling in Instruments, zombies must not be counted as live, which is why I couldn't figure out why I was seemingly running out of memory when the number of live bytes wasn't climbing. However, when I upgraded to XCode 5, the new memory gauge showed that I was quickly racking up memory, and then when I dropped into Instruments, Leaks was covered up by a warning that said that it would not work properly since NSZombies were enabled. So, I disabled zombies, and now my memory usage is staying constant, just like I expected it to.

Related

iOS Application Crash while UIImage loading (virtual memory not cleaning up)

I have a weird crash in my application without any trace. this is probably a memory related problem but with very little information & I'm not sure how to proceed or fix it. If it wasnt for instruments would have been left with no clue what so ever.
I have an image array (in this example an array of size 2) where I load an image, create an image context & draw and save it into the array. Everytime the method is called image array objects are replaced with the new content. In instruments I see a very huge Virtual Memory usage during this method call & apparently after each call memory is not cleared & hence crashes. The project is ARC. I'll list down code below. This is all we need to recreate this issue. (the image I'm using is little big in size about 7MB, so its easier to recreate crash). Also i'm using iPad2 device.
+ (UIImage *)imageCopy:(UIImage *)src
{
UIGraphicsBeginImageContext(src.size);
[src drawAtPoint:CGPointZero];
UIImage *r = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return r;
}
- (IBAction)buttonTouch:(id)sender
{
for (int i=0; i<2; i++)
{
if (i==0)
{
self.mImage = [UIImage imageNamed:#"LARGE_elevation.jpg"];
}
else
{
self.mImage = [UIImage imageNamed:#"LARGE_elevation2.jpg"];
}
// imageArray is a NSMutableArray with capacity of 2
[imageArray setObject:[ViewController imageCopy:self.mImage] atIndexedSubscript:i];
}
((UIImageView *)[self.view viewWithTag:100]).image = self.mImage;
}
Here is a screen from instruments where it crash on 2nd time after memory warnings are issued.
I dont see any big issue with the "imageCopy" method I'm using here.
Any help on this is really appreciated.
Thanks & Cheers,
I found out that it was a cyclic reference issue. So when new content replaces the old content in the array, the past objects were still remaining. It was quite an interesting finding because in the memory leaks analyser it showed up as few KB data leak which you wont suspect as the non freed virtual memory was few hundred Megabytes (MB).
As a very abstract example.
ClassA
#property (strong) ClassB *obj
----------
ClassB
#property (strong) ClassA *obj
- (id)initWithA:(ClassA *)objA;
----------
So when you remove A neither object will be deallocated properly. In my case leak traced by the leak analyser was few KB for both of the objects even though the CoreGraphics calculations were hanging onto about 200MB data in virtual memory.
Fix was to mark the A reference in ClassB as weak.
ClassB
#property (weak) ClassA *obj
- (id)initWithA:(ClassA *)objA;
Verdict
Never under estimate a memory leak, no matter how big or small & arc or mrc
The problem is probably that the method imageNamed: caches the images loaded, and there is apparently no way to clear the cache after a memory warning programmatically.
Instead of imageNamed:, you could use other methods like initWithData: that do not cache the images. You will find a detailed discussion here.

Objective-C - Instruments shows leak for array, even with ARC

The following function shows a leak in Instrument (Leak) - Xcode, even with the code commented out as shown below.
void function () {
NSArray *devices = [AVCaptureDevice devices];
// I have used devices here..but I commented to check leak.
devices = nil;
}
Responsible library is AVFoundation. I'm using ARC.
Instruments doesn't show where objects are being leaked - it shows where the object that is being leaked is being created.
What you can do is to look at how you manage the memory of devices and make sure that you are releasing it correctly.
It's odd that it's showing a leak under ARC - so it would be useful to see some relevant code to see what is being done.

Cocos2d v2 + Chipmunk : Fails when adding shapes to a CCLayer

I'm very experienced with Cocos2d and Box2d, and wanted to try Chipmunk instead. Everything works fine as long as I add sprites to the helloworldlayer, but if I add another layer and attempt to add a sprite to that new layer it crashes.
It fails with an EXC_BAD_ACCESS in the cpSpaceStep function call in the update on the main layer.
-(void) update:(ccTime) delta
{
// Should use a fixed size step based on the animation interval.
int steps = 2;
CGFloat dt = [[CCDirector sharedDirector] animationInterval]/(CGFloat)steps;
for(int i=0; i<steps; i++){
HERE -> cpSpaceStep(space_, dt);
}
}
EDIT:
The problem seems to be regarding sprite batch nodes and not CCLayers.
Chipmunk doesn't actually interact directly with Cocos2D, it's just a physics engine. So if it's crashing in cpSpaceStep() with an EXC_BAD_ACCESS it's almost certainly because you gave Chipmunk a dangling pointer somewhere or have another memory bug that's corrupting data that Chipmunk is using.
If you compile it as debug, where does it crash exactly? Are you using any callbacks at all and are sure it's not happening in one of those?

Deallocating object while in background thread

I have been working on iOS project, which used data downloading in background. Well, honestly say - implementation wasn't the best one (and was changed later to remove such nonobvious pattern), and I've got some problems with not-deallocated objects, and can't say, that docs gave me a clear understanding of what's going on. Code, demonstrating common idea:
- (void)loadModelAtIndex:(NSUInteger)index {
Model *model = [self modelAtIndex:index];
if (model) {
model.index = index;
[self performSelectorInBackgroundThread:#selector(loadModelInBackgroundThread) withObject:model]
}
}
- (void)loadModelInBackgroundThread:(Model *)model {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
model.data = [NSData dataWithContentsOfURL:model.url];
//and some other changes can be here
[self performSelectorOnMainThread:#selector(modelDidLoad) withObject:model waitUntilDone:NO]'
[pool drain];
}
- (void)modelDidLoad:(Model *)model {
[self saveModel:model atIndex:model.index];
[self loadModelAtIndex:model.index + 1];
}
Well, almost all time it has been working as expected. Except if caller has beed deallocated while downloading in background - Model object stayed in memory, without being released (I've got growing memory at this point).
Can anyone explain me, what will happen in case of deallocation, while background thread is running? I'm not sure this code can be suitable at all, but still interested. Any modification will make things run well?
Except if caller has beed deallocated while downloading in background - Model object stayed in memory
the performSelector | …Thread… calls retain their arguments. If your objects are deallocated in that time, the problem lies elsewhere. Run with zombies enabled to locate it - you can record every reference count.

NSOperation not being fully deallocated? Live Bytes not less than Overall Bytes in Allocations Utility despite operations completing

I'm running a large number of NSOperation tasks and my application is using a great deal of memory. While it should use quite a bit, it's using magnitudes more than it should, and I'm thinking, from Instruments, that it's because the NSOperation objects aren't being fully deallocated. The code for my NSOperation subclass is as such:
- (id)initFromNode:(BKObject *)sender withNumber:(NSNumber *)number; {
self = [super init];
if (self) {
_number = [number retain];
_sender = [sender retain];
}
return self;
}
- (void)main {
[_sender go:_number];
}
- (void)dealloc {
[_number release];
_number = nil;
[_sender release];
_sender = nil;
[super dealloc];
}
My suspicions are as such because in Instruments, when I use the Allocations utility, it shows enormous amounts of data for my _NSOperationInternal and also my subclasses of NSOperation, but the Live Bytes number is always equal to the Overall Bytes number. I've also checked with the Leaks utility, which never finds any memory leaks. I'm careful about releasing any operation objects after adding them to the queue.
I also stuck in a completion block to test it out if it actually finishes, and I can confirm that at least some of them do. Confirming all of them would be more work, and the live data in Instruments should go down a bit, even if only, say 10% of them, were finishing.
I'm at a loss. Let me know if any of my understanding of what I'm doing is off or if more code would be helpful. Do you know what might be going on that this is using more memory than it should?
To debug this, try to see if -dealloc gets even called. The simplest way to do this is to use an NSLog, the correct way would be a breakpoint.
My guesses are:
You're not correctly releasing the NSOperations.
or you've got retain cycles.
Some objects in your NSOperation don't get released, try adding an autorelease pool around your main method.