4

我有以下形式的ARC代码:objective-c内存管理 - 对象保证存在多久?

NSMutableData* someData = [NSMutableData dataWithLength:123]; ...

CTRunGetGlyphs(run, CGRangeMake(0, 0), someData.mutableBytes); ...

const CGGlyph *glyphs = [someData mutableBytes]; ...

...后面的代码读取内存从glyphs,但没有任何与someData,它不再被引用。请注意,CGGlyph不是对象类型,而是无符号整数。

难道我不必担心someData的内存在我完成glyphs(实际上只是指向someData)之前可能会被释放吗?

所有这些代码都在同一范围内(即单个选择器),并且glyphssomeData都在同一时间超出范围。

PS在这个问题的早期草稿中,我提到了'垃圾收集',这并没有真正适用于我的项目。这就是为什么下面的一些答案给予了与ARC下发生的事情同等的待遇。

+5

您是否真的在启用GC的情况下运行?你不得不打开它,它已经(预先)弃用了。或者你在谈论ARC,这不是GC? –

+0

乔希问一个好问题。 GC!= ARC。 – MikeS

+0

按要求更正。 – Merk

回答

1

截至2012年夏季的,东西都在变化为该返回非对象类型的内部指针苹果对象的过程。在release notes的山狮,苹果说:

NS_RETURNS_INNER_POINTER

方法,返回指针(比目标C对象除外) 已装饰着铿锵编译器属性 objc_returns_inner_pointer(与铿锵编译时)以防止 编译器主动释放那些不再被引用的那些 消息的接收器表达式,而返回的 指针可能仍在使用中。

检查NSData.h头文件表明这也适用于iOS 6以上。

还要注意的是NS_RETURNS_INNER_POINTERclang规范定义为__attribute__((objc_returns_inner_pointer)),这使得它使得

对象的生存期将延长至至少最早的:最后使用 返回指针,或从它派生的任何指针, 在调用函数中; 或自动释放池被恢复到以前的状态 。

注意事项: 如果你使用任何旧的然后山狮或iOS 6你仍然需要使用任何这里讨论的方法(例如,__attribute__((objc_precise_lifetime)))宣布当地的NSData和NSMutableData对象时。

此外,即使使用最新的编译器和Apple库,如果您使用旧的或第三方库的对象不装饰他们的内部指针返回方法与__attribute__((objc_returns_inner_pointer))您将需要修饰您的本地变量声明这样的对象与__attribute__((objc_precise_lifetime))或使用答案中讨论的其他方法之一。

2

以下是一般性答案,不一定反映Objective-C GC支持。但是,包括重新计数在内的各种GC实现可以被认为是可达性,抛开怪癖。


在GC语言,一个目的是保证,只要它是Strongly-Reachable存在;这些Strong-Reachability图的“根”可能因语言和执行环境而异。 “强”的确切含义也有所不同,但通常意味着边是强参考。 (在手动参考计数场景中,每条边都可以被认为是来自给定“所有者”的无法匹配的“保留”。)

CLR/.NET上的C#就是一个这样的实现,其中变量可以保留在范围,但不能作为可达性图的“根”。见Systems.Timer.Timer类并查找GC.KeepAlive

如果定时器是在长时间运行的方法声明中,使用保持活动,以防止垃圾收集的发生[计时器对象]的方法结束之前。

3

在实际的,真正的垃圾回收代码可能是一个问题。如果对象不再有任何引用,对象可能会被释放,并且如果您再也不使用它,编译器可能会随时丢弃引用。为了达到最优化的目的,范围仅仅是为这种事情设置一个上限的方法,而不是绝对的方式。

您可以使用NSAllocateCollectable将生命周期计算附加到C原语指针,尽管它很混乱且稍微复杂。

垃圾收集从未在iOS中实现过,现在在Mac上不推荐使用(在this FAQ的底部引用),两种情况都支持自动引用计数(ARC)。ARC增加了retain s和releases,它可以看到它们是隐含需要的。不幸的是,它可以执行一些以前不可能的巧妙技巧,比如从autorelease池中检索对象,如果它们被用作返回结果的话。因此,这与垃圾收集方法具有相同的净效果 - 对象可能在最终引用消失后的任何时候释放。

一种解决方法是创建一个类,如:

@interface PFDoNothing 

+ (void)doNothingWith:(id)object; 

@end 

这是实现什么也不做。完成使用内部存储器后,将您的自动释放对象发布给它。 Objective-C的动态调度意味着编译器优化调用是不安全的 - 它无法知道你(或KVO机制或任何其他actor)在运行时没有做过像调用方法那样的东西。

编辑:NSData是一种特殊情况,因为它提供了直接的C级访问对象保存的内存,所以至少找到GC情况的明确讨论并不困难。尽管与上述相同,但请参阅this thread on Cocoabuilder,即不要使用垃圾回收,并且自动引用计数的行为不同。

+1

我已经做了一些挖掘,并重新:“假设没有手动池管理和其他一切正常,你的[NSMutableData dataWithLength:123]肯定会持续,只要当前ARC下的方法”,其他来源似乎不同意,包括上面的@CRD引用的讨论,以及http://clang.llvm.org/docs/AutomaticReferenceCounting.html。 “...自动存储持续时间的局部变量没有精确的生命周期语义。” – Merk

+0

@Merk我认为你是对的,我以前的回答是错误的。因此,我编辑了它,以防止错误持续存在。向所有人道歉。 – Tommy

4

你是潜在无论你使用GC还是像其他人推荐的那样使用GC。你正在处理的是内部指针,它不被认为是,它在GC或ARC中一般都拥有引用 - 除非该实现具有特殊的外壳NSData。如果没有自己的引用,GC或ARC可能会删除该对象。你面临的问题是内部指针特有的。

当你描述你的情况时,最安全的事情就是坚持真正的参考。您可以通过将NSData引用分配给实例变量或static(方法本地,如果您愿意)变量,然后在完成内部指针时将nil分配给该变量来完成此操作。在static的情况下要小心并发!

实际上,你的代码可能在GC和ARC中都可以工作,可能在ARC中更有可能,但是在编译器改变的时候,或者可以想见咬你。对于一个变量声明和一个额外任务的成本,您可以避免这个问题,便宜的保险。

[见this讨论,ARC下寿命短的一个例子。]

+0

谢谢,那个牧场牧场的讨论有所帮助。所以#1。有一个问题。 #2。有3种建议的方法可以解决这个问题:(a)你的伊娃尔建议(b)objc_precise_lifetime限定词(c)在该函数结束时自动调用[someData self]。从清晰度和维护角度来看,你的伊娃建议可能是最简单的。 – Merk

+0

我在下面的答案讨论了Apple最近处理内部指针的方法。如果你喜欢它,欢呼声并加油。 – Merk