了解内存管理保留计数

时间:2015-08-19 05:45:28

标签: ios objective-c

我有一个即时变量" obj1"在MyClass.h中。

@property (nonatomic, retain) NSMutableArray *arrObj1;

在MyClass.m viewDidLoad 方法中,我已经分配了另一个对象" obj2"并将其分配给obj1。

 - (void)viewDidLoad {
    [super viewDidLoad];
    NSMutableArray *arrObj2 = [[NSMutableArray alloc] initWithObjects:@"a",@"b",@"c", nil];
    NSLog(@"arrObj2 count %lu",(unsigned long)[arrObj2 retainCount]);
    self.arrObj1 = arrObj2;

    NSLog(@"arrObj1 count %lu",(unsigned long)[self.arrObj1 retainCount]);
    NSLog(@"arrObj2 count %lu",(unsigned long)[arrObj2 retainCount]);
}

这是输出

2015-08-19 11:06:14.461 MyClass[1812:24133] arrObj2 count 1
2015-08-19 11:06:16.332 MyClass[1812:24133] arrObj1 count 2
2015-08-19 11:06:17.327 MyClass[1812:24133] arrObj2 count 2

我没有得到arrObj2如何保留计数值2。 请解释一下。

谢谢

7 个答案:

答案 0 :(得分:4)

您问题的一个更相关的问题是:为什么arrObjarrObj2似乎共享属性?答案是他们对同一个对象的两个引用。这意味着同一个数组在同一个地方被强烈引用;也就是说,arrObj1arrObj2实际上是同一个数组。这就是为什么你看到retainCount为2的原因,尽管你不应该使用retainCount。 (稍后会详细介绍。)比较调试器中数组的地址;他们将是一样的。如果您将一个对象添加到一个数组,它将被添加到"另一个数组。"

您可以通过在属性声明中使用副本或将self.arrObj1 = arrObj2更改为self.arrObj1 = [arrObj2 mutableCopy]来解决此问题。 (编辑:我实际上并不确定更改要复制的属性类型会对此有所帮助,因为它是一种可变类型。但如果它只是NSArray,它将起作用。)

我希望能回答你的问题,但现在我想解释为什么这是错误的问题。请不要采取任何冒犯行为,因为学习这一点非常重要而且不容易。 :)

考虑关系类型,而不是保留/释放

您根本不应该考虑保留计数,而是考虑strongweak关系:strong关系表示对象的所有者权益,weak关系不会,并且在删除对象中的所有所有者权益后不久将转换为nil。另请注意,不推荐使用retain属性类型:它在ARC代码中应为strong

不要使用retainCount

不要使用retainCount。或者,如果您愿意,When to use Retain Count

  

从不。

然后是Apple的official documentation,它开始于:

  

此方法在调试内存管理问题时没有任何价值。

或者this from bbum,我认为它更好。他详细介绍了为什么retainCount无用,最后得出结论:

  

底线:绝对retainCount唯一可以用于分析目的的唯一时间是,如果您具有导致当前保留计数值的每个保留和释放的回溯(还有另一个用例,最后记录) 。如果你有这个,那么你不需要保留计数,幸运的是,Instruments已经非常擅长为你生成每个对象的保留和发布库存。

基本上,它的价值没有用。它将返回(在某些情况下)保留对象而不释放对象的次数。它不会(也不能)将其自动释放的次数考虑在内。并且它不会总是返回"正确的"即使不考虑自动释放也是有价值的,因为某些对象永远不能从RAM中释放出来。

答案 1 :(得分:0)

在Objective-C中,对象是引用类型。

保留计数在第一次分配对象时增加。 当对象分配给arrObj1时,当属性声明为retainstrong时,不会复制对象,因此arrObj1arrObj2包含指向同一个对象。属性arrObj1的隐式setter第二次增加了保留计数器。

答案 2 :(得分:0)

内存管理是管理对象生命周期并在不再需要时释放它们的编程规则。

管理对象内存是性能问题;如果应用程序不释放不需要的对象,则其内存占用增加并且性能受损。

不使用垃圾回收的Cocoa应用程序中的内存管理基于引用计数模型。创建或复制对象时,其保留计数为1。

此后,其他对象可能表示您对象的所有者权益,这会增加其保留计数。

对象的所有者也可以放弃对其的所有者权益,这会减少保留计数。当保留计数变为零时,对象将被释放(销毁)。

检查此图片。

https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/Art/memory_management.jpg

希望得到这个帮助。

答案 3 :(得分:0)

声明后

self.arrObj1 = arrObj2;

变量arrObj2和属性self.arrObj1指向完全相同的对象。

如果他们指向同一个对象,并且arrObj2的引用次数为2,那么您希望self.arrObj1具有哪些引用计数?

答案 4 :(得分:0)

保留计数的原因是2,因为你使用了保留NSMutableArray * arrObj1,所以实际上 当你分配arrObj2时,保留计数变为1, 当你将它分配给arrObj1作为具有保留属性时,计数增加 - 变为2。 arrObj2与arrObj1相同,因为你没有复制它(如上面的答案所指出的Steven Fisher)两者都有相同的保留计数。

如果你让arrObj1指定属性,那么count将保持为1。

答案 5 :(得分:0)

简单地说,arrObj2 指向的对象是arrObj1指向的同一对象。仪器向我们显示,当您调用initWithObjects时,此对象获得+1保留计数:

enter image description here

当你调用setArrObj1时(即你使用self.arrObj1 = ...语法),它得到+2保留计数:

enter image description here

有关使用乐器“分配”工具跟踪内存使用情况的演示,请参阅WWDC 2013视频Fixing Memory Issues和WWDC 2012视频iOS App Performance: Memory。最重要的是,虽然在“分配”工具中有效地找到正确的对象需要一些练习,但这个“记录引用计数”功能对于找到对所讨论对象的强引用的位置非常有用。

我确定你已经看过了,但我也会推荐你Advanced Memory Management Programming Guide

答案 6 :(得分:-1)

当你分配一个新的内存区域(我称之为M)并将其分配给obj2时,M的retainCount为1。

当你这样做时:self.obj1 = obj2。 因为self.obj1是一个保留属性,所以M将保留+1,所以现在它的retainCount = 2。

导致obj1& obj2是对M的引用,所以它们的retainCount是2。

尝试[obj1 release]并再次获取obj2的retainCount以进行检查。

希望它有所帮助。