我使用以下代码创建了一个数组。在不再需要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
答案 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,但阅读您的代码的任何人都知道它附属于一个属性。
1)创建一个UIImage子类,并在dealloc中添加一个日志语句。您将创建MyImages(子类),而不是创建UIImages,这意味着您需要在任何您想要使用它的子类.h文件(在调试时将其放在pch文件中)。首先查看图像是否已释放。如果没有,你知道你的问题。
2)子类NSArray(不是NSMutableArray,不是你真的不需要上面显示的代码中的可变数组)。如果有必要使用可变数组的原因,那么在设置ivar时,首先使用[MyArray arrayWithArray:theMutableArray]。记录dealloc。
现在运行测试。数组或图像未被释放。一旦知道了哪个,就可以追踪保留问题。
有一句古老的谚语,我会对它进行屠宰,但它就像是,当你尝试一切可能导致问题的原因,并且不能解决问题时,那就必须是你认为这不是实际问题。