开发者

objc leak behavior I can't explain

开发者 https://www.devze.com 2023-01-24 16:46 出处:网络
The following code loop does not leak memory (as verified by watching it loop infinitely under \"top\");

The following code loop does not leak memory (as verified by watching it loop infinitely under "top");

NSBitmapImageRep *this_bmap = 0;

while (1) {

  CGImageRef windowImage = 
     CGWindowListCreateImage(CGRectNull,
                             kCGWindowListOptionIncludingWindow,
                             windowID, kCGWindowImageDefault);

  this_bmap = [[NSBitmapImageRep alloc] initWithCGImage:windowImage];

  [this_bmap release];
  CGImageRelease(windowImage);
}

and I would not expect it to. However, when I copy a pointer to the bitmap data, like this:

NSBitmapImageRep *this_bmap = 0;

while (1) {

  CGImageRef windowImage = 
     CGWindowListCreateImage(CGRectNull,
                             kCGWindowListOptionIncludingWindow,
                             windowID, kCGWindowImageDefault);

  this_bmap = [[NSBitmapImageRep alloc] initWithCGImage:windowImage];

  void *pixels1 = [this_bmap bitmapData];

  [this_bmap release];
  CGImageRelease(windowImage);
}

this now leaks like crazy. I can see this happening rapidly under "top" and the program eventually grinds to a halt.

I am new to Objective-C, but I am not new to programming and I can't understand this behavior. The documentation for the method bitmapData claims it simply returns a pointer (as 开发者_如何学Copposed to allocating something), so I am stumped. I found a similar question from some time ago, but the only answer was to "look into pools" and I don't see how that could help here.

Any ideas what's going on here?


Accessing the pixel data causes the object to be retained and autoreleased so that the bitmap data doesn't suddenly go away unexpectedly. To see your expected results (i.e., loop not consuming memory with each iteration), rewrite as:

NSBitmapImageRep *this_bmap = 0;

while (1) {
  NSAutoreleasePool* loopPool = [NSAutoreleasePool new];
  CGImageRef windowImage = 
     CGWindowListCreateImage(CGRectNull,
                             kCGWindowListOptionIncludingWindow,
                             windowID, kCGWindowImageDefault);

  this_bmap = [[NSBitmapImageRep alloc] initWithCGImage:windowImage];

  void *pixels1 = [this_bmap bitmapData];

  [this_bmap release];
  CGImageRelease(windowImage);
  [loopPool drain];
}


hmmm, I'm no guru so I'm just guessing here. But it occurs to me that every time through to loop you are effectively declaring a new variable called pixels1. Therefore each time through you allocate some new space rather than reuse it. Try moving the declaration of pixels1 outside the loop and see what happens.

Note, this is just a guess and may be wrong. A more knowledgable person may be able to give you a definitive answer.


The "initWithCGImage:" call has this in its documentation:

Discussion

If you use this method, you should treat the resulting bitmap NSBitmapImageRep object as read only. Because it only retains the value in the cgImage parameter, rather than unpacking the data, accessing the pixel data requires the creation of a copy of that data in memory. Changes to that data are not saved back to the Core Graphics image.

That seems to indicate that the memory returned from bitmapData needs to be CFRelease'ed.

0

精彩评论

暂无评论...
验证码 换一张
取 消