我的iOS应用程序存在内存问题,我对此有几个问题。
首先,我正在使用iOS 6,而我正在使用ARC。
现在让我解释一下我的情况:
我有2个观点。从第一个视图开始,如果我点击一个按钮,我会创建第二个视图(使用alloc
和init
)并使用此代码将其显示为模式:
[self presentViewController:secondView animated:YES completion:^{
[secondView prepareToDraw]; // Function I use to start my computations and rendering
}];
在某些时候,当计算完成时,我想关闭第二个视图并返回第一个视图。我在第二个视图中使用了这段代码:
[self dismissViewControllerAnimated:YES completion:^{
[self finished]; // Function I use to free some malloc
}];
我使用Instruments Allocations和Leaks运行我的应用程序,我没有泄漏。
以下是我didReceiveMemoryWarning
的代码:
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
if ([self isViewLoaded] && ([[self view] window] == nil)) {
self.view = nil;
[self tearDownGL];
if ([EAGLContext currentContext] == self.context) {
[EAGLContext setCurrentContext:nil];
}
self.context = nil;
}
// Dispose of any resources that can be recreated.
NSLog(@"Resources freed");
}
tearDownGL
函数释放OpenGLES资源,如纹理,顶点数组......
当我运行我的应用程序时,在第一个和第二个视图之间进行多次切换后,我收到内存警告,然后我的应用程序崩溃。
以下是我的问题:
1 - 应用程序是否会自动释放我的控制器的UIImage,UIView,...如果没有,我如何在使用ARC时释放它们?
我也看到了viewDidUnload
函数,但它已被弃用,因为文档说:
从内存中释放控制器视图时调用。 (不推荐使用 在iOS 6.0中。在低内存条件下,视图不再被清除 所以永远不会调用此方法。)
但是如果在低内存条件下不再清除视图,我如何释放更多内存以防止我的应用程序崩溃? 我该怎么办?
2 - 我在我的2个控制器的didReceiveMemoryWarning
函数上放了一个断点。当我在模拟器上运行应用程序时,我模拟了内存警告。
我可以看到{2}控制器调用didReceiveMemoryWarning
一次。
但是如果我在第一个和第二个控制器之间切换几次,didReceiveMemoryWarning
将被调用一次用于我的第一个视图控制器,但是为我的第二个视图控制器调用了几次。如果我切换3次,该功能将被调用3次。所以我想,当我“关闭”我的第二个视图回到第一个视图时,第二个视图没有被释放并且仍然存在。为什么?我怎么能强迫它被摧毁? (因为我不再使用它并创建一个新的)
我在函数中创建了第二个视图控制器,但我没有对它进行任何引用(它没有存储在类中)。
答案 0 :(得分:1)
ARC并不总是意味着图像,视图等会立即被释放。它被添加到最近的弧池并被释放。如果应用程序可能需要它或在某个地方使用它,它将被添加到主池中,只有在应用程序终止时才会释放它。因此,如果您认为它已经达到了目的,那么最好自己移除它。特别是在图像的情况下,它仍然留在存储器中,因为它不知道它是否被其他地方使用。
答案 1 :(得分:1)
您应该释放(在ARC中,这意味着将所有强引用设置为nil)所有内存(图像,NSData对象,数组,模型层所代表的所有数据等),这些内存当前不是必需的,并且可以(easiyl)重新显示 - 再次使用时创建。所有其他代码都应该以一种方式编写,即如果在内存警告期间释放了那些对象,那么将检查属性/ iVar是否为nil,然后将重新创建。
我怀疑self.view
是可能被处置的对象之一。
您可能已经显示了UIImageView。这是用UIImage对象创建的probalby。在显示UIImageView时,你并不是真的需要内存中的UIImage。 (如果UIImageView仍然需要它,那么它会保留它或在其onw上保留一个强引用,这样你就不必担心保留图像本身。)这是要发布的资源。
如果self.context
属于处置资源,我不能说。它可能是。
答案 2 :(得分:1)
每当你使用块时,你应该使用弱引用self,因为这可能导致保留周期。所以将代码更改为:
__weak typeof(self) blockSelf = self;
[self dismissViewControllerAnimated:YES completion:^{
[blockSelf finished]; // Function I use to free some malloc
}];
此外,您释放任何内容的代码应该是dealloc。如果它只发生在该控制器的生命周期结束时,则不需要自定义方法。
你的第一个电话似乎也错了:
[self presentViewController:secondView animated:YES completion:^{
[secondView prepareToDraw]; // Function I use to start my computations and rendering
}];
如果prepareToDraw
仅发生一次,则第一次出现控制器时,应该在viewDidLoad
中运行此代码。这也有利于您的体系结构,因为只有控制器本身应该知道它在开始时要设置什么,以及最后的tearDown。
希望有所帮助。也许您的代码中还有其他/更多问题。
答案 3 :(得分:1)
请查看自动续费池:AutoReleasePools
它的内容如下:
使用本地自动释放池块来减少峰值内存占用
许多程序会创建自动释放的临时对象。这些对象会添加到程序的内存占用空间,直到块结束。在许多情况下,允许临时对象累积直到当前事件循环迭代结束时不会导致过多的开销;但是,在某些情况下,您可能会创建大量临时对象,这些对象会大大增加内存占用,并且您希望更快地处置。在后面这些情况下,您可以创建自己的自动释放池块。在块结束时,临时对象被释放,这通常会导致释放,从而减少程序的内存占用
我有一个类似的问题,我在@autoreleasepool
块中封装了我想要删除的所有大型对象。