5

我有一个很大的 malloc 区域,我想将它包装在一个 NSData 对象中。一段时间后,我复制了那个 NSData 对象。我希望这两个 NSData 对象具有独立的生命周期。ARC 负责对 NSData 对象本身进行引用计数,但我试图澄清包含的 malloc'd region的生命周期。这是一个代码草图:

float* cubeData = (float*)malloc(cubeDataSize);
printf("cubeData=%p\n", cubeData);
// cubeData=0x01beef00

for (...) { /* fill the cubeData array */ }

NSData* data = [NSData dataWithBytesNoCopy:cubeData length:cubeDataSize
  freeWhenDone:YES];

NSData* data2 = [data copyWithZone:nil]

printf("data.bytes=%p data2.bytes=%p\n", data.bytes, data2.bytes);
// data.bytes=0x01beef00 data2.bytes=0x01beef00

copyWithZone 不会对 malloc 的区域进行深度复制,这对我来说没问题——[NSData dataWithData:]如果我想要深度复制,我可以使用。我不清楚(我不确定如何最好地测试)是哪个 NSData 对象拥有底层的 malloc'd 缓冲区?如果它们都持有对 malloc 缓冲区的引用(使用某种形式的不透明引用计数),那就太好了!但是,如果在释放data对象时释放了 malloc 的缓冲区(如 暗示的那样freeWhenDone:YES),data2则会遇到麻烦。

有人可以解释 NSData 在这种情况下的作用吗?或者,有人可以建议一个明确的测试来向自己证明发生了什么吗?

4

1 回答 1

1

对于根本问题:

NSData 的内容是否单独引用计数?

不。(但是看看你的代码,这应该没关系。在这个转移之后见下文。)

--- 开始分流 ---

ARC 通过在适当的时间发送等效的retain和消息来管理 Objective-C 对象的保留和释放。release“适当的时间”是在编译时通过代码检查确定的。这正是它所做的一切。当您开始创建指向这些对象(即)的非对象片段的指针时bytes,您需要自己管理生命周期。

@CouchDeveloper 提供了有关objc_precise_lifetime. 在处理内部指针时,将此属性放置在数据对象上可以保护您免受 ARC 优化,但在这里并不真正相关。的重点objc_precise_lifetime是告诉 ARC 在引用变量超出范围之前不允许释放对象。它解决的问题如下所示:

NSData *data = ...;
void *stuff = data.bytes; // (1)
doSomething(stuff); // (2)

ARC 有一个优化,它允许data在第 (1) 行和第 (2) 行之间进行破坏,因为data即使data在范围内,您也永远不会再次引用。添加objc_precise_lifetime属性会禁止该优化。当您开始NSData大量使用时,此属性会变得很重要。

--- 结束转移 ---

好的,但是你的情况呢?

float* cubeData = (float*)malloc(cubeDataSize);
NSData* data = [NSData dataWithBytesNoCopy:cubeData length:cubeDataSize freeWhenDone:YES];
NSData* data2 = [data copyWithZone:nil]

这段代码运行后,有两种可能性(大多数时候你不应该关心这是真的,因为它们是不可变的对象):

  • data并且data2都是指向同一个NSData对象的强指针。该对象拥有分配的内存,并在解除分配时将其释放。(这是在这种特殊情况下几乎肯定会发生的情况,但这是一个实现细节。)
  • data指向NSData拥有分配内存的对象,并在释放时释放它。data2指向NSData具有自己内存的不同对象(释放时将释放。)

(还有其他选项;可能NSData使用底层dispatch_data或写时复制方案。但所有选项从外部看起来都应该像上面那样。)

在第一种情况下,如果data超出范围,但data2仍然存在,则NSData保留所有权。没问题。在第二种情况下,当data超出范围时,它会破坏它的内存,但data2有一个独立的副本,所以再次没有问题。

我认为你的困惑来自data拥有记忆的想法。它没有。指向的NSData对象拥有内存。并且只是指针。datadatadata2

于 2013-07-15T21:47:16.053 回答