【问题标题】:Memory usage does not drop -- no leaks though内存使用量没有下降——虽然没有泄漏
【发布时间】:2011-02-09 03:16:41
【问题描述】:

我有 UINavigationController 控制几个视图。其中一个视图由 20 个可滚动页面组成。每个页面都是通过添加按钮、标签、UIImageViews 等从 UIViews 动态构建的。当这个 UIView 从堆栈中弹出时,内存使用量保持不变。因此,如果我继续推动/弹出该视图,它会不断上升。

在我的 dealloc 中,我遍历所有 20 页并找到通过 addSubview 添加的每种类型的对象,然后对其进行释放,但仪器说我的内存使用量永远不会下降!我正在尝试使用“retainCount”来查看我正在释放的对象的情况,但我可能无法通过 retainCount 获得真实情况。对于某些元素,retainCount 显示为 2,因此我尝试释放该对象两次,但随后应用程序崩溃。如果我一旦它工作就释放它但内存使用量永远不会下降:(

Q1:我是否需要遍历找到每个元素,然后对该元素进行释放?为什么我不能释放一个父对象,它所包含的所有对象都会自动释放?

Q2:retainCount 是一个可靠的指标吗?

【问题讨论】:

  • 进一步调试。这是我到目前为止发现的。我有一个 UIScrollView,我在其上添加了 20 个 UIViews 对象。同样的 20 个 UIView 被添加到 NSMutableArray。仪器告诉我,当视图弹出时,20 个 UIView 中的每一个都仍然悬而未决。好的,虽然我必须忘记从某个地方“释放”它,所以保留计数必须增加。我发现确实有一个地方。所以就在 [self.scrollView addObject:page] 行之后; //page 是我添加的 UIView [page release];但是现在在我释放 self.scrollView 应用程序崩溃时释放 NSMutableArray 之后。
  • 在 NSZombieEnabled 之后,我看到了这个错误 *** -[CFString release]: message sent to deallocated instance 0x3ea6f00 Found NSStackLoggingNoCompact=1 将有助于以某种方式使用“info malloc”查看与崩溃中的地址关联的变量-history 0x3ea6f00' 执行此操作后,我看到一个堆栈跟踪,它指向我分配 NSMutableArray 的目标视图中的一行。我将此数组传递给正在弹出的视图。我想可能我只需要“保留”正在传递的数组,但这并没有帮助。应用程序继续崩溃并指向同一行。我从来没有被困得这么厉害:(

标签: iphone memory-management


【解决方案1】:

解决了这个问题。以下是上周困扰我的一些谜题。

20 个 UIView 对象都被一个 UIScrollView 和一个数组 NSMutableArray 引用。从一个人身上释放它们并没有完全释放它们,因为它们仍然被另一个人引用。 确保在将它们添加到 UIScrollView 后,我在每个 UIView 上调用 release,因此保留计数保持为 1。

这 20 个 UIView 中的每一个都在内部使用从前一个视图传递给它们的数组——通过一个简单的指针。在传递的数组中使用对象后,我也释放了它们。因此,在修复了上面的保留计数后,当我终于释放整个视图(通过弹回上一个视图)时,应用程序开始崩溃,并出现类似的消息 * -[CFString release]: 消息发送到释放的实例 0x3ea6f00

通过 NSStackLoggingNoCompact=1 跟踪它们 有人告诉我,我传递给我之前推送到堆栈上的视图的数组存在一些问题,我刚刚再次弹出。但我无法追踪到哪里。我确实尝试增加整个数组的保留,但这并没有帮助,因为我没有对数组内的对象进行保留。

无论如何,我终于找到了我从传递的数组中释放对象的有问题的代码。我将其更改为复制数组的内容,现在应用程序没有崩溃并且所有视图都被释放。呸!

【讨论】:

    【解决方案2】:

    您确定您正在查看净字节数吗?如果您不小心查看了整体字节,那将永远不会下降。 Net bytes 是您的应用程序当前分配的字节数。

    当你释放一个父对象时,它需要释放它在 dealloc: 中拥有的所有东西。如果您在那里释放主视图,则该视图将释放其所有子视图(如果它被释放)。

    此外,retainCount 通常不是一个可靠的指标。由于 UIKit 和 Foundation 的底层特性,追踪保留计数可能是一项艰巨的任务。 Apple 的许多类将保留和释放对象,您将无法找出发生的地点和时间。

    【讨论】:

    • 确实在查看净字节数。我确实在将视图推送到导航控制器后立即执行发布。当按下后退按钮时,我这样做 [self.navigationController popToViewController:[[self.navigationController viewControllers] objectAtIndex:[sender selectedSegmentIndex]] animated:YES];会不会是 popToViewController 以某种方式没有释放当前视图?
    • popToViewController 将返回一个弹出的控制器数组。尝试遍历该数组并释放所有这些视图控制器。
    • @rickharrison:这样做是 / 非常 / 坏主意。最好预先做好内存管理: c = [[UIController alloc] init...]; [navController pushViewController:c aanimated:YES]; [c 释放];
    • 返回的数组只包含一个视图本身,显然不能对其进行发布。你在 dealloc 中真正做什么?如果我尝试显式释放容器 UIView 应用程序崩溃,但如果我不这样做,这些相同的视图将保留在内存中。例如,有一个 UIView 对象仪器说我在一个地方做了一个 malloc,将它添加到一个数组,并将它作为子视图添加到另一个对象。每次我做 addsubview 或 addobject 我都会提前发布。然而,这个物体仍然悬而未决。显式释放它会导致崩溃。看起来很混乱。
    • 无论何时使用 addSubview:添加它的视图都会保留它。然后你释放它,这样你就不再拥有它的所有权了。然后,当您释放父视图时,它将向其所有子视图发送释放消息。同样,当你释放一个视图控制器时,你应该在 dealloc: 中释放父视图,这样它就可以释放它的所有子视图。
    猜你喜欢
    • 2013-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-13
    • 2020-05-14
    相关资源
    最近更新 更多