【问题标题】:iPad Memory LimitationsiPad 内存限制
【发布时间】:2012-02-07 07:07:03
【问题描述】:

我正在开发的应用程序相对简单,但它会引发内存警告。我试图弄清楚应用程序设计是否需要太多内存并且应该重新设计和分解以减少使用量,或者应用程序设计很好但应用程序本身臃肿并且错误地占用了比需要更多的内存。

应用程序从 Web 下载一个包含一组问题的 XML 文件,然后生成一个 UIScrollView 来显示问题控件列表。每个问题控件都有一个 UITextView 和一个 UISegmentedControl、UIButton、UITableView、UITextField 或四个带有 UIButton(自定义日期控件)的 UITextField。截图如下:

此设置适用于较小的问题集,但应用程序开始引发内存警告,其中包含超过 120 个问题的较大集。这是在更大的集合上使用 Allocations 和 VM Tracker Instruments 的典型运行:

在 xml 下载和模型加载时,Allocations 内存会出现峰值,但直到 Allocations 内存达到稳定状态后才会发出警告。 VM Tracker 内存在它们被抛出时仍在增加,这让我认为控件仍在加载到内存中,并且 VM Tracker 是内存增长导致警告的更好指标。当驻留大小大于 125 MB 时,通常会出现警告。 我找到了一种方法可以显着降低 Resident 的大小。问题控件有一个自定义视图,可以为它们提供圆角边缘和阴影。如果我从自定义视图中注释掉 drawRect 代码(如下所示),分配内存保持不变,但驻留大小下降约 30 MB,并且不会增长到 93 MB 以上。我可以为这些问题找到一个较轻的背景,但如果我能减少它的内存占用,我更愿意保留圆角边缘和阴影。

- (void)drawRect:(CGRect)rect {
    // get the contect
    CGContextRef context = UIGraphicsGetCurrentContext();

    //for the shadow, save the state then draw the shadow
    CGContextSaveGState(context);
    CGContextSetShadow(context, CGSizeMake(4,-5), 10);

    //now draw the rounded rectangle
    CGContextSetStrokeColorWithColor(context, [[UIColor blackColor] CGColor]);  

    if(_HighlightColor==nil){
        _HighlightColor = [[UIColor whiteColor] retain];
    }
    CGContextSetFillColorWithColor(context, _HighlightColor.CGColor);

    //since I need room in my rect for the shadow, make the rounded rectangle a little smaller than frame
    CGRect rrect = CGRectMake(CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetWidth(rect)-30, CGRectGetHeight(rect)-30);
    CGFloat radius = 5;
    // the rest is pretty much copied from Apples example
    CGFloat minx = CGRectGetMinX(rrect), midx = CGRectGetMidX(rrect), maxx = CGRectGetMaxX(rrect);
    CGFloat miny = CGRectGetMinY(rrect), midy = CGRectGetMidY(rrect), maxy = CGRectGetMaxY(rrect);

    // Start at 1
    CGContextMoveToPoint(context, minx, midy);
    // Add an arc through 2 to 3
    CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
    // Add an arc through 4 to 5
    CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
    // Add an arc through 6 to 7
    CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
    // Add an arc through 8 to 9
    CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
    // Close the path
    CGContextClosePath(context);
    // Fill & stroke the path
    CGContextDrawPath(context, kCGPathFillStroke);

    //for the shadow
    CGContextRestoreGState(context);
}

仪器和内存警告看起来像是内存已用尽,但这些数字对我来说似乎很高。我不认为滚动视图中的 120 个这些问题控件对 iPad 来说是个问题,但我没有关于它们应该使用多少内存的参考框架。考虑到 iPad 可以运行的一些图形密集型游戏,上面的简单 drawRect 代码似乎不会在问题控件中占用超过 30 MB 的空间。这种内存使用率是否看起来很高,或者这是否是您对具有这么多简单 UI 元素的应用程序的期望? drawRect 中是否有一些会占用大量内存的内容或有关如何优化它的任何建议?如果这看起来应该最大化 iPad 的内存,我将创建选项卡或页面并限制我放在选项卡/页面上的问题数量,以便一次仅将一小部分控件加载到内存中。但是,如果 iPad 应该能够在内存中处理它们,我宁愿不分解它们。非常感谢任何输入。

【问题讨论】:

    标签: objective-c ios memory-warning


    【解决方案1】:

    您分配的每个视图都会占用大量内存。当您在屏幕上(或在滚动视图中的屏幕外)有很多视图时,避免使用大量内存的方法是拥有一个您可以重复使用的视图池,在任何时候都只比屏幕上的视图多一些。

    坏消息:这种缓存和交换的设置非常复杂。

    好消息:UITableView 帮你搞定!

    当你拥有任意数量的 UIViews 时,最好的解决方案几乎总是将它们放入一个 table view 中,然后让 Apple 来完成这项工作。

    【讨论】:

    • 所以你认为我所说的浏览量实际上会占用这么多内存吗?我已经考虑过您建议的视图池,但认为不断确定需要加载和卸载哪些视图会很滞后且过于复杂。 UITableView 的好主意!这将解决第二个问题。希望视图生成足够轻,可以跟上滚动。我会试一试,然后告诉你。谢谢!
    • @Wes 视图占用了相当多的内存;我相信每个人都会保留所有像素的缓冲区以进行合成。如果您的视图生成速度非常慢,您可以为每种类型的行提供自己的标识符(使用 initWithStyle:Identifier: 和 deque...WithIdentifier:)。这样,您只需生成每种类型几次,其余时间您只需填写数据。我从未真正尝试过嵌套表格视图,但我不明白为什么它不应该工作。
    【解决方案2】:

    您可以使用heap shot analysis(使用 Instruments)来监控内存增量,直至分配回溯详细信息——这应该让您对什么在增长以及为什么增长有足够的了解。这些分配通常表明您在此期间还应该销毁什么。

    还要确保您的程序没有泄漏。

    【讨论】:

    • 感谢您的建议。我已经用它来将内存恢复到现在的位置,这是一个非常有用的工具。希望不知道的人会看到您的帖子并试一试。
    猜你喜欢
    • 1970-01-01
    • 2011-11-11
    • 2011-09-05
    • 2013-08-22
    • 1970-01-01
    • 2019-11-09
    • 2010-09-26
    • 2014-07-16
    • 2011-02-25
    相关资源
    最近更新 更多