我有一个用C ++和Objective-C编写的应用程序。 C ++部分从远程摄像机接收数据并调用Objective-C回调(Block)进行显示。 Objective-C已启用ARC。
当加载显示视图时,我将一个块设置为C ++部分,当数据到来时,C ++将调用此块来更新显示。
代码如下:
- (void)viewDidLoad
{
__weak CameraVC *weakSelf = self;
self.callback_func = ^int(int iWidth, int iHeight, int iDataLen, void *pData) {
NSData *data = [NSData dataWithBytes:pData length:iDataLen];
[weakSelf performSelectorOnMainThread:@selector(updateDisplayWithData:)
withObject:data waitUntilDone:YES];
return 0;
};
setDisplayCallback(self.callback_func);
}
- (void)updateDisplayWithData:(NSData *)data
{
self.imageView.image = [UIImage imageWithData:data];
}
setDisplayCallback()
是一个用于设置回调的C ++函数。
当应用程序运行时,在xcode面板中显示应用程序内存使用情况,并且它总是在增加,几小时后,应用程序崩溃,我认为是内存泄漏?
我试着评论代码:
// self.imageView.image = [UIImage imageWithData:data];
内存泄漏停止了。
问题1 是否存在导致此内存泄漏的周期?
我试图替换以下代码:
self.callback_func = ^int(int iWidth, int iHeight, int iDataLen, void *pData) {
NSData *data = [NSData dataWithBytes:pData length:iDataLen];
[weakSelf performSelectorOnMainThread:@selector(updateDisplayWithData:)
withObject:data waitUntilDone:YES];
return 0;
};
为:
self.callback_func = ^int(int iWidth, int iHeight, int iDataLen, void *pData) {
NSData *data = [NSData dataWithBytesNoCopy:pData length:iDataLen freeWhenDone:YES];
[weakSelf performSelectorOnMainThread:@selector(updateDisplayWithData:)
withObject:data waitUntilDone:YES];
return 0;
};
内存泄漏问题减少了,但仍然存在。
问题2 dataWithBytes
和dataWithBytesNoCopy
之间有什么区别?
更新
我尝试使用no-ARC设置此单个文件,并修改代码:
- (void)viewDidLoad
{
self.callback_func = ^int(int iWidth, int iHeight, int iDataLen, void *pData) {
@autoreleasepool {
NSData *data = [NSData dataWithBytes:pData length:iDataLen];
[self performSelectorOnMainThread:@selector(updateDisplayWithData:)
withObject:data waitUntilDone:YES];
}
return 0;
};
setDisplayCallback(self.callback_func);
}
内存使用情况稳定。我很好奇ARC版本代码中的问题是什么。
答案 0 :(得分:1)
按向后顺序:
-dataWithBytes...
和-dataWithBytesNoCopy...
之间的区别在于名称。通常,如果使用原始字节数组创建NSData,NSData将在内部复制所有字节,以便它知道其基础数据不能独立修改(并且它也可以管理内存,但它想要)。如果您使用...NoCopy
变体,则告诉NSData使用您将其作为存储的缓冲区,而不是再分配。这当然没有使用任何更多的内存(对于更大的缓冲区来说很重要),但是你需要更加小心你需要什么指针以及之后用指针做什么。如果你在这里传递的是freeWhenDone
的YES,那么你告诉NSData在它自己被解除分配时调用指针上的free()
。这假定它是直接从malloc
分配的,并有效地将malloc缓冲区的所有权转移到NSData。
代码中是否有保留周期?不,没有明显的一个。
因此,您所看到的内容取决于您所说的"泄漏",周围代码中还发生了什么,以及您希望看到的内容。您似乎正在做的是从pData
获取字节,将它们复制到NSData或将其所有权转移到NSData,然后使用该数据创建UIImage
,并将其放入UIImageView
。 应如何处理NSData
的内存管理取决于您未显示的pData
的所有权。 (谁是mallocs呢?谁应该释放它?什么时候?)。从图像数据创建UIImage当然会使用内存,但不会泄漏"它。如果您对此进行评论,那么您肯定会使用更少的内存,但显然无法获得图像。 :)(NSData本身将在-performSelector...
完成之后被释放,因为它在之后超出范围,在两种情况下都使用缓冲区。)