2010-11-13 64 views
3

下面的代码循环不会泄漏内存(通过观察它在无限循环下“top”)来验证;objc泄漏行为我无法解释

NSBitmapImageRep *this_bmap = 0; 

while (1) { 

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

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

    [this_bmap release]; 
    CGImageRelease(windowImage); 
} 

我不会期待它。然而,当我复制一个指针位图数据,像这样:

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); 
} 

这现在泄漏像疯了似的。我可以看到这种情况在“最高层”下迅速发生,该计划最终陷入停滞。

我是新来的Objective-C,但我不是新手编程,我无法理解这种行为。方法bitmapData的文档声明它只是返回一个指针(而不是分配内容),所以我很难过。我从前一段时间发现了一个类似的问题,但唯一的答案是“调查泳池”,但我不明白这对此有何帮助。

任何想法这里发生了什么?

回答

0

嗯,我不是大师,所以我只是猜测在这里。但是对我而言,每次进行循环时,您都会有效地声明一个名为pixels1的新变量。因此,每次通过你分配一些新的空间,而不是重复使用它。尝试移动循环外的像素1的声明并查看会发生什么。

请注意,这只是一个猜测,可能是错误的。一个更有知识的人可能会给你一个明确的答案。

+1

貌似我错了:-) – drekka 2010-11-13 04:08:22

0

的“initWithCGImage:”电话有这样的说明文件中:

讨论

如果使用这种方法,你 应该把所生成位图 NSBitmapImageRep对象为只读。 由于它只保留 中的值而不是 解包数据,因此需要在内存中创建该数据的 副本。对该数据的更改 不会保存回 核心图形图像。

这似乎表明从bitmapData返回的内存需要CFRelease'ed。

+1

不,因为从bitmapData返回的指针不是CF对象。尝试'CFRelease'会导致崩溃。 – 2010-11-13 06:17:35

7

访问像素数据会导致对象被保留和自动释放,以便位图数据不会突然消失。若要查看您的预期结果(即循环不会消耗每次迭代的内存),请重新编写为:

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]; 
} 
+0

这工作。我不明白,所以我有一些功课要做。非常感谢你。 – rwa 2010-11-13 04:30:33

+0

没有太多的功课要做。当池被排空/释放时,自动释放的对象被放入池中以被释放。这发生在运行循环中正在处理的每个事件结束时(即,一旦您的整个调用堆栈在接收事件后完成)。如果你有这样一个紧密的循环,池会很快被填满,直到整个循环(以及它后面的所有调用)完成之后才会排空。为循环的每次迭代创建和排空新的自动释放池意味着池永远不会变得如此之大。 – d11wtq 2010-11-13 06:02:29