如何跟踪内存峰值? (峰值是p,而不是l). [英] How can I track down memory peaks? (That's peaks with a p, not an l.)

查看:193
本文介绍了如何跟踪内存峰值? (峰值是p,而不是l).的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个信息亭应用程序,该应用程序本质上显示了一堆幻灯片,上面有各种各样的信息.一年多以前,当我开始进行Objective-C和iOS开发时,我就开始对此进行编码.我发现我的代码风格比现在的代码风格更加简洁,而且我的经验更加丰富,因此我决定从头开始重写.

我使用分配"工具运行了我的应用程序,以查看内存使用量.考虑到这是一个自助服务终端应用程序,因此所有内容都需要运行流畅,无泄漏. (当然,所有应用程序都需要在运行时没有泄漏,但是信息亭应用程序使这成为一个更为重要的目标.)我看到了一些有趣的结果,因此我也运行了旧版本的代码.

运行代码的较旧版本,我发现甚至有大约1.15 MB的内存使用率运行.一切似乎都已根据需要分配和释放.但是,在新的实现中,我看到了一些不同的东西.内存使用率一直在小幅上升"中跳跃,然后最终达到约1.47兆字节的使用率峰值.运行10个小时以上后,新的分配"报告如下所示:

我担心的原因有几个.

  1. 运行开始时的奇怪模式.
  2. 分配似乎达到1.47兆字节的峰值,但是整夜运行表明,随着时间的推移,它实际上会慢慢使用越来越多的内存.那不是好事.

旧项目和新项目之间存在几个显着差异.

  • 较早的版本使用Plists作为后备存储(我手动读取和写入plist文件.)新项目使用Core Data.

  • 新项目实现了一个库,该库在旧项目没有的每个幻灯片"上都被调用.我会更担心这个库,除了我写了它,然后遍历了它以确保我发布了所有内容,并且只在不可能手动发布的情况下才自动发布.

  • 两个类都使用工厂类来创建幻灯片.在旧项目中,工厂类是单例.我认为将其设置为普通类将有助于解决内存问题,因为单例从未发布过. (因此它的属性没有被释放.在新项目中,工厂类被释放了,所以我不确定为什么它仍然占用了所有内存(如果这就是引起问题的原因. /p>

  • 旧项目在各个地方都使用了字符串常量.新代码对同一件事使用了一个庞大的枚举. (新代码通常使用更多常量.)

如何跟踪内存峰值?

如果有人能帮助我指出正确的方向,我将不胜感激.

看起来似乎是由于调用 KosherCocoa 图书馆.如果有人介意看看它,并告诉我我在内存管理方面在做什么错,我真的会很感激.

我该如何追踪内存峰值?记忆都在 当应用程序丢弃正在使用的所有内容时,由应用程序进行清理, 但这似乎并没有丢弃任何东西.

这是遗弃物品"或使用量增加"的典型情况.也就是说,您有一个应用程序,该应用程序在运行时会在内存中建立对象图,这是正常使用情况的一部分.对象没有泄漏,因为它们仍然连接到活动对象图.这些对象很有可能是某种类型的高速缓存(通常是只写高速缓存)的一部分,或者是涉及历史状态的机制的一部分(撤消堆栈是潜在的堆积来源).

要修复此问题,您需要确保在应用运行时正确修剪了对象图.缓存通常应使用最近最少使用的[LRU]修剪算法,该算法会限制缓存大小.如果缓存键无效,则该数据也应被修剪.

对于历史信息,修剪历史至关重要.因此,请确保历史数据包含该历史状态的绝对最小表示形式.

使用Heapshot分析-它的创建是为了帮助准确地跟踪这类问题.

我写了详细的操作方法"指南;

I'm concerned for several reason.

  1. The odd pattern in the beginning of the run.
  2. Allocations seems to peak at 1.47 megabytes, but running it overnight shows that it actually will slowly use more and more memory over time. That can't be a good thing.

There are several notable differences between the old project and the new one.

  • The older one uses Plists as a backing store (I manually read and write to a plist file.) The new project uses Core Data.

  • The new project implements a library that is called on each "slide" that the old project didn't have. I'd be more concerned about this library, except I wrote it and I went through it to make sure I was releasing everything and only autoreleased wherever manual releases were impossible.

  • Both classes use a factory class to create the slides. In the old project, the factory class was a singleton. I thought that making it into a normal class would help with the memory issues, since the singleton was never released. (Hence it's properties were not being released.In the new project, the factory class is being released so I'm not sure why it's still taking up all that memory (if that's what's causing the problem.

  • The old project makes use of string constants in various places. The new code uses a massive enum for the same thing. (The new code in general uses more constants.)

What can I do to track down memory peaks? The memory is all being cleaned up by the application when it discards whatever it's using, but it doesn't seem to be discarding things until the app terminates.

I'd be grateful if anyone would help point me in the right direction.

Edit:

It looks like the peaking is being caused by calls to the KosherCocoa library. If anyone would mind taking a look at it and telling me what I'm doing wrong there as far as memory management goes, I'd really appreciate it.

解决方案

What can I do to track down memory peaks? The memory is all being cleaned up by the application when it discards whatever it's using, but it doesn't seem to be discarding things.

This is a classic case of "abandoned objects" or "usage accretion". That is, you have an application that, as it runs, builds up an object graph in memory as a normal part of usage. The objects aren't leaked because they are still connected to the live object graph. More likely than not, the objects are a part of either some kind of a cache (a write-only cache, most often) or a mechanism involving historical state (the undo stack is a potential source for accretion).

To fix it, you need to make sure your object graph is pruned appropriately as your app runs. Caches should generally use a least-recently-used [LRU] pruning algorithm that limits the cache size. If a cache key ever goes invalid, that data should be pruned, too.

For historical information, pruning the history is critical. So is making sure that the historical data contains an absolutely minimal representation of that historical state.

Use Heapshot analysis -- it was created to help track down exactly these kinds of problems.

I wrote a detailed "How to" guide; When is a Leak not a Leak?

这篇关于如何跟踪内存峰值? (峰值是p,而不是l).的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆