今天 Widget 每次刷新都会占用更多内存,然后最终崩溃

Posted

技术标签:

【中文标题】今天 Widget 每次刷新都会占用更多内存,然后最终崩溃【英文标题】:Today Widget uses more memory each time it refreshes, then eventually crashes 【发布时间】:2018-04-10 15:34:47 【问题描述】:

我正在开发一个 Today Widget,但遇到了内存问题。

当我运行小部件并监控 Xcode 的内存使用情况时,小部件在第一次启动时使用了大约 15MB。然后,当我从小部件屏幕滑开并返回时,它会增加到大约 16MB。

每次我滑动并返回它时,内存使用量都会增加大约 0.5–1.5MB。随着我做的更多,我收到内存警告(didReceiveMemoryWarning() 被调用),最终,随着更多的滑动,小部件崩溃。

所有这些症状都是在 iPhone X 上进行测试时发生的。在模拟器上,小部件开始使用大约 50 兆字节,这看起来有点奇怪,但它具有相同的行为,每次我滑开时内存使用量都会增加并向后滑动。

我尝试使用 Instruments 对此进行分析,但我只能让 Instruments 显示开始时发生的情况(当我第一次启动小部件时),并且在我滑开和滑回时它不会继续运行。

通过消除过程(注释掉我的小部件的实际功能),当只保留 UI 代码时,问题仍然存在。 这让我觉得这是我的 UI 方法的问题。

我过去构建过 Today Widgets,但一直使用 Interface Builder。这次我决定改为以编程方式构建界面。当我查看我使用 Interface Builder 构建的其他 Today Widgets 时,我没有看到每次刷新都会增加内存使用的相同行为。

首先,我将所有 UI 元素设置为私有惰性变量,如下所示:

private lazy var mainStackView: UIStackView = 
    let stackView = UIStackView()
    stackView.distribution = .fillEqually
    stackView.translatesAutoresizingMaskIntoConstraints = false
    return stackView
()

然后,在viewDidLoad() 中,我将我的视图添加到TodayViewController 的视图中,并带有一些约束,如下所示:

view.addSubview(mainStackView)

let stackViewLeadingConstraint = mainStackView.leadingAnchor.constraintEqualToSystemSpacingAfter(view.leadingAnchor, multiplier: 1)
let stackViewTopConstraint = mainStackView.topAnchor.constraintEqualToSystemSpacingBelow(view.topAnchor, multiplier: 1)
let stackViewTrailingConstraint = view.trailingAnchor.constraintEqualToSystemSpacingAfter(mainStackView.trailingAnchor, multiplier: 1)
let stackViewBottomConstraint = view.bottomAnchor.constraintEqualToSystemSpacingBelow(mainStackView.bottomAnchor, multiplier: 1)

view.addConstraints([stackViewLeadingConstraint, stackViewTopConstraint, stackViewTrailingConstraint, stackViewBottomConstraint])

由于我不熟悉以编程方式构建 UI,这种方法是否存在明显不正确且可能导致内存泄漏的问题?

我什至尝试注释掉我的所有代码并使用基本空白UIViewController 运行它,其中视图生命周期函数甚至不做任何事情,我仍然遇到内存泄漏。这让我觉得当我以编程方式构建界面时我应该做一些我没有做的事情。

每次出现 Today Widget 时,似乎有些东西没有被释放并且在内存中被复制。如果我能找到任何关于如何找到没有被释放的东西并强制系统释放的建议,我将不胜感激它。谢谢!


已解决

感谢 Christopher Pickslay 提供的故障排除提示,我能够找到问题所在。原来是我的错。为了解决以前不相关的问题,我在方案中打开了 Zombie Objects,但我仍然启用了它。一旦我关闭它,问题就消失了。这是我正在谈论的设置:

【问题讨论】:

我遇到了同样的问题,当我打开我的扩展程序时,我的僵尸仍然被禁用,它会保持添加内存,然后在第 5 次尝试时崩溃。你能帮我解决这个问题吗? 【参考方案1】:

我认为您构建 UI 的方式没有任何问题(从您目前分享的内容来看)。尝试使用 Memory Graph Debugger 而不是 Instruments 来查找您的泄漏。

它将暂停调试器,您可以使用顶部栏浏览所有位置以及指向每个实例的位置。打开内存图调试器,查看您的图,然后取消暂停并在屏幕上滚动扩展程序几次,然后再次打开内存图调试器。这应该让您更好地了解什么在泄漏,什么在持续。

【讨论】:

非常感谢您的指导!通过遵循这一点,我能够确定我仍然在方案中启用了“僵尸对象”,这是解决另一个问题时遗留下来的。一旦我禁用,问题就消失了。

以上是关于今天 Widget 每次刷新都会占用更多内存,然后最终崩溃的主要内容,如果未能解决你的问题,请参考以下文章

session_start() 每次刷新都会创建新会话 [重复]

maven无论怎么刷新都没反应

js把数字存在cookie里,每次刷新都增加1

单例模式

Golang中切片复制成本,一个大切片会比小切片占用更多内存吗?

如何关闭百度安全检测