记忆未完全释放

时间:2016-09-17 16:04:09

标签: objective-c automatic-ref-counting

我刚开始使用SceneKit和SpriteKit和ARC创建了一个应用程序。我注意到当我在不同的视图之间切换时,内存使用量正在迅速增加。我的第一个想法是我有内存泄漏,但我现在不确定。这个行为甚至发生在这个基本的例子中:

for(int r=0;r<9999999;r+=1){
    NSString *s=[NSString stringWithFormat:@"test%i",r];
    s=nil;
}

根据我的理解,创建了NSString对象并在此循环中直接释放。我在iPhone-Simulator和iPhone上尝试了这个例子,它使得应用程序在执行此循环后使用数百MB的RAM。 (我正在使用Xcode调试导航器检查内存使用情况)

我显然误解了一些事情。为什么这个例子后来仍然保留记忆?

修改

您还可以创建一个新项目:iOS - &gt;游戏 - &gt;游戏技术:SceneKit

然后将其添加到viewDidLoad:

for(int r=0;r<999999;r+=1){
    SCNNode *tn=[SCNNode node];
    tn=nil;
}

内存将达到550MB并且下降到300MB,如果对象完全释放并从RAM中删除,这将是很多。

1 个答案:

答案 0 :(得分:1)

  1. 不要依赖NSString进行内存诊断。它具有相当不典型的行为。

    这是一个不常见的场景,我在S.O.上看过的场景。不止一次,为了将一些复杂的内存问题简化为更简单的事情,开发人员使用NSString创建了一个简化的示例,而不知道选择该特定类会引入奇怪的,不相关的行为。新的“调试内存图”工具或旧的经过验证的仪器(下面讨论过)是诊断一个代码中潜在问题的最佳方法。

  2. 顺便说一下,你谈到立即释放物品。如果您的方法不是以allocnewcopymutableCopy开头,则退出的对象将在后立即解除分配范围,因为它们是autorelease个对象。它们在自动释放池耗尽之前不会被释放(例如,你回到运行循环中)。

    因此,如果您的应用程序的“高水位”标记太高,但内存最终会回落到可接受的水平,那么请考虑选择自动释放对象(和/或引入您自己的自动释放池)。但一般来说,这种自动释放与非自动释放对象的区别在某种程度上是学术性的,除非你有一个很长的循环循环,在这个循环中你要在返回运行循环之前分配许多对象。

    简而言之,自动释放对象不会影响对象是否已取消分配,而只会影响它们是否已取消分配。我只是提到这个以响应大for循环和争用对象应该立即释放。解除分配的确切时间受到自动释放对象的影响。

  3. 关于您的应用程序中的快速内存增加,它可能与您的示例完全无关。诊断这一点的方法是使用仪器(如WWDC 2013 Fixing Memory Issues中所述)。简而言之,选择“产品” - “配置文件”并选择“泄漏”工具(它将获取必要的“分配”工具),锻炼应用程序,然后精确查看已分配和未发布的内容。 / p>

    此外,Xcode 8的“调试对象图”工具也非常有用,而且更易于使用。它在WWDC 2016的Visual Debugging with Xcode中有所描述。使用此工具,您可以在左侧面板中看到对象列表,当您选择一个对象时,您可以看到与该对象关联的对象图,因此您可以诊断可能仍有的未解析的引用:

    enter image description here

  4. 顺便说一下,您可以尝试模拟内存警告。 Cocoa对象执行各种缓存,其中一些缓存在内存压力时被清除。

  5. 如果您打开了方案中的任何内存调试选项(例如,僵尸),请注意这些选项会导致额外的内存增长,因为它会捕获相关的调试信息。在分析泄漏,放弃或缓存的内存之前,您可能需要关闭所有调试选项。

  6. 最重要的是,如果您看到每次迭代增加了几kb并且没有实例化的对象出现并且您没有打开任何调试选项,那么您可能不必担心它。许多Cocoa对象正在进行各种缓存,这些缓存超出了我们的控制范围,通常可以忽略不计。但是如果内存在每次迭代时都是通过mb或gb增长(并且不用担心第一次迭代,而只是后续的迭代),那么你需要仔细查看。