NSMutableArray导致内存累积,而不是使用ARC自动释放

时间:2013-05-07 11:10:56

标签: ios cocoa memory

我使用以下代码创建了一个数组。在不再需要12个图像之后,我将imageArray设置为nil并将一组新图像重新加载到此数组中。当我在乐器中运行应用程序时,我可以看到内存堆积问题。我也运行了快照,它显示12个图像仍然挥之不去,即使我将数组设置为零。我也尝试在自己的autorelease池中初始化这个数组,认为它是以某种方式在主线程下面的一个独立线程上创建的。那也行不通。有什么想法吗?

ViewController.h

@property (strong, nonatomic) NSMutableArray *imageArray;

ViewController.m

- (void) firstSetOfImages{
  imageArray= [[NSMutableArray alloc] initWithObjects:wordImage1, wordImage2, wordImage3, wordImage4, wordImage5, wordImage6, wordImage7, wordImage8, wordImage9, wordImage10, wordImage11, wordImage12, nil];
}

- (void) clearImages{
  [self setImageArray:nil];
  [imageArray removeAllObjects];
  [self secondSetOfImages];
}

- (void) secondSetOfImages{
    imageArray= [[NSMutableArray alloc] initWithObjects:wordImage1, wordImage2, wordImage3, wordImage4, wordImage5, wordImage6, wordImage7, wordImage8, wordImage9, wordImage10, wordImage11, wordImage12, nil];
}

以下是在加载1组12张图像和第2组12张图像之间拍摄1张照片的示例。

Snapshot    Timestamp   Heap Growth # Persistent
Heapshot 3  00:39.457.174   53.02 KB    800
 < non-object >     26.05 KB    277
 UIImageView        3.38 KB 36
 CFDictionary (mutable)     3.38 KB 72
 CFBasicHash (key-store)        2.83 KB 73
 CFBasicHash (value-store)      2.83 KB 73
 NSPathStore2       2.25 KB 12
 CGImageReadRef     1.88 KB 12
 CALayer        1.69 KB 36
 CGImage        1.62 KB 13
 CFNumber       1.31 KB 84
 CGImagePlus        1.31 KB 12
 CFData     1.12 KB 24
 CGImageProvider        768 Bytes   12
 CGDataProvider     720 Bytes   5
 UIImage        576 Bytes   12
 CFString (immutable)       416 Bytes   13
 CFArray (mutable-variable)     384 Bytes   12
 CGImageReadSessionRef      192 Bytes   12
 _   UIImageViewExtendedStorage     192 Bytes   4
 __NSArrayM     160 Bytes   5   
     CFDictionary (immutable)       48 Bytes    1

编辑:

我修改了代码并使数组成为一个ivar。我拿了另一个仪器分配样本。以下是我的快照的更详细的显示。每次用12张新图像重置数组时,我都会拍摄一张快照。每个快照都有大约35kb的堆积增长。

Snapshot    Timestamp       Heap Growth     # Persistent
Heapshot 4  00:58.581.296       35.63 KB        680
 < non-object >                 13.02 KB        220
 CFDictionary (mutable)         3.38 KB         72
 CFBasicHash (key-store)        2.81 KB     72
 CFBasicHash (value-store)      2.81 KB     72
 NSPathStore2                   2.28 KB     12
 CGImageReadRef                 1.88 KB     12
 CGImage                        1.50 KB     12
 CFNumber                       1.31 KB     84
 CGImagePlus                1.31 KB     12   
 CFData                     1.12 KB     24
 UIImageView                1.12 KB     12
 CGImageProvider            768 Bytes       12
 UIImage                    576 Bytes       12
 CALayer                    576 Bytes       12
 CFString (immutable)       384 Bytes       12
 CFArray (mutable-variable) 384 Bytes       12
 CGImageReadSessionRef      192 Bytes       12
 CGDataProvider             144 Bytes       1
 _UIImageViewExtendedStorage96 Bytes        2
 __NSArrayM                 32 Bytes        1

这是UIImage中其中一个Persistent项的堆栈跟踪。它没有指向创建它的特定代码行。不确定从哪里开始?

  24 FourGameCenter 0x4b4bf
  23 FourGameCenter 0x4b538
  22 UIKit UIApplicationMain
  21 GraphicsServices GSEventRunModal
  20 CoreFoundation CFRunLoopRunInMode
  19 CoreFoundation CFRunLoopRunSpecific
  18 CoreFoundation __CFRunLoopRun
  17 CoreFoundation __CFRunLoopDoSource1
  16 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
  15 GraphicsServices PurpleEventCallback
  14 GraphicsServices _PurpleEventCallback
  13 UIKit _UIApplicationHandleEvent
  12 UIKit -[UIApplication sendEvent:]
  11 UIKit -[UIWindow _sendTouchesForEvent:]
  10 UIKit -[UIControl touchesEnded:withEvent:]
   9 UIKit -[UIControl(Internal) _sendActionsForEvents:withEvent:]
   8 UIKit -[UIControl sendAction:to:forEvent:]
   7 UIKit -[UIApplication sendAction:toTarget:fromSender:forEvent:]
   6 UIKit -[UIApplication sendAction:to:from:forEvent:]
   5 FourGameCenter 0x8d7fa
   4 FourGameCenter 0x71830
   3 FourGameCenter 0x797e6
   2 libobjc.A.dylib _objc_rootAllocWithZone
   1 libobjc.A.dylib class_createInstance
   0 libsystem_c.dylib calloc

4 个答案:

答案 0 :(得分:2)

您无法在clearImages中执行以下操作:

[self setImageArray:nil];
[imageArray removeAllObjects];

在上面的代码段中,您只需将imageArray设置为nil即可。然后,您无法向nil对象发送removeAllObjects消息:它只会默默地执行任何操作。

您需要将行重新排序为:

[imageArray removeAllObjects];
[self setImageArray:nil];

答案 1 :(得分:1)

[self setImageArray:nil]

将自动删除图像对象,因此无需执行removeObjects。

但是,如果您在其他地方的UIImageViews中使用这些图像,并且在其他地方的视图中保留或使用这些UIImageView,您还需要从superview中释放/删除UIImageView。

[imageView removeFromSuperview];

或者如果您在阵列中有UIImageViews:

[imageViewArray makeObjectsPerformSelector:@selector(removeFromSuperview)];

答案 2 :(得分:0)

检查您是否在方案中启用了僵尸:诊断。虽然僵尸不太可能在ARC之下,但该项目可能仍会启用,这使得检查内存泄漏看起来像是一切都在泄漏。

答案 3 :(得分:0)

你在这里混合隐喻 - 你使用一个属性但是把它设置成一个ivar - 它可能会产生泄漏。此外,如果您释放数组,则不必释放每个对象,因为它会为您执行此操作。

所以,使用ivar

@MyClass...
{
  NSMutableArray *imageArray;
}

现在您可以将其设置为新阵列,并确保旧阵列已发布。如果要完全释放数组,只需将其设置为nil。

或者,如果要使用属性,则在更改对象时,请使用:

self.imageArray = ...;

现在,第二个问题 - 您的代码直接访问imageArray(没有前导“_”) - 您是否使用相同的名称合成了ivar?这可能不是一个好主意,因为它只会让人们在阅读您的代码时感到困惑。如果你只是放弃@synthesize,你现在可以免费获得ivar作为属性名称,前面加上“_”。您可以直接访问该ivar,但阅读您的代码的任何人都知道它附属于一个属性。

编辑:您显然没有发布您认为自己的对象。您的问题与this one非常相似。您需要做的是:

1)创建一个UIImage子类,并在dealloc中添加一个日志语句。您将创建MyImages(子类),而不是创建UIImages,这意味着您需要在任何您想要使用它的子类.h文件(在调试时将其放在pch文件中)。首先查看图像是否已释放。如果没有,你知道你的问题。

2)子类NSArray(不是NSMutableArray,不是你真的不需要上面显示的代码中的可变数组)。如果有必要使用可变数组的原因,那么在设置ivar时,首先使用[MyArray arrayWithArray:theMutableArray]。记录dealloc。

现在运行测试。数组或图像未被释放。一旦知道了哪个,就可以追踪保留问题。

有一句古老的谚语,我会对它进行屠宰,但它就像是,当你尝试一切可能导致问题的原因,并且不能解决问题时,那就必须是你认为这不是实际问题。