2

我的数据可视化应用程序在重绘期间会出现大量内存消耗峰值(触发 drawRect 的 setNeedsDisplay)。我目前正在重绘包含数据图的整个视图。此视图比设备显示大得多。

有没有办法告诉 CoreGraphics 分配足够的内存来绘制每个元素(每个元素都是一个比设备显示小得多的小矩形块)并在完成后释放内存,而不是我目前的幼稚方法?

提前致谢。

-道格

更新 12 月 8 日美国东部标准时间上午 8:28

这是带有解释性文字的相关代码。我正在运行具有 ObjectAlloc、内存监视器和泄漏仪器的仪器。我唯一的内存泄漏与 NSOperationQueue 没有释放内存有关。这是次要的,不相关的。

在架构上,该应用程序由一个 tableView 组成,其中包含人类基因组中要检查的有趣位置列表。When a table row is selected I enqueue a data gathering operation that returns data called alignmentData. 然后将该数据绘制为水平矩形板。

最初,当 tableView 启动时,我的内存占用为 5 MB。

- (void)viewWillAppear:(BOOL)animated {

    // Initial dimensions for the alignment view are set here. These
    // dimensions were roughed out in IB.

    frame                       = self.alignmentView.frame;
    frame.origin.x              = 0.0;
    frame.origin.y              = 0.0;  
    frame.size.width            = self.scrollView.contentSize.width;    
    frame.size.height           = 2.0 * (self.containerView.frame.size.height);

}

注意:viewWillAppear: 调用后内存占用没有变化。即使alignmentView 的大小远远超出显示器的尺寸。

这是从数据收集操作中调用的方法。

- (void)didFinishRetrievingAlignmentData:(NSDictionary *)results {

        // Data retrieved from the data server via the data gathering operation
    NSMutableData *alignmentData = [[results objectForKey:@"alignmentData"] retain];

    NSMutableArray *alignments = [[NSMutableArray alloc] init];
    while (offset < [alignmentData length]) {

        // ...
        // Ingest alignmentData in alignments array 
        // ...  

    } // while (offset < [alignmentData length])    
    [alignmentData release];

    // Take the array of alignment objects and position them in screen space 
        // so that they pack densely creating horizontal rows of alignment objects 
        // in the process.
    self.alignmentView.packedAlignmentRows = 
    [Alignment packAlignments:alignments basepairStart:self.startBasepairValue basepairEnd:self.endBasepairValue];  
    [alignments release];

    [self.alignmentView setNeedsDisplay];

}

在这行代码之后:

self.alignmentView.packedAlignmentRows = ...

内存占用为 13.8 MB

在这行代码之后:

[self.alignmentView setNeedsDisplay];

内存占用飙升至 21.5 MB,停留几秒钟,然后返回到预先存在的 13.8 MB 水平

我正在寻找的解决方案将允许我从本质上创建一个水平渲染缓冲区窗口,该窗口是单行对齐对象的高度。我会将它的内存渲染分配给它,然后丢弃它。我会一遍又一遍地为每一行对齐数据执行此操作。

从理论上讲,我可以使用这种方法渲染无限量的数据,这当然是最出色的 ;-)。

-道格

4

5 回答 5

6

这是 - 我的记忆问题的不太明显的答案。我会给自己这个,因为我是在苹果开发论坛上从 Rincewind 上学到的——顺便说一句,这是一位非常乐于助人的苹果工程师。

事实证明,通过将大视图分割成 N 个小块并依次渲染到每个小块中,我将导致内存峰值大约为大视图大小的 1/N。

因此,对于每个较小的视图:alloc/init,提供我的一部分数据,setNeedsDisplay。冲洗/重复所有 N 个小视图。

很简单吧?

在学习这个之前,我错误地认为 setNeedsDisplay:myRect 这样做是为了大视图。显然不是。

感谢所有的建议帮派。

干杯,道格@dugla

于 2009-12-09T11:42:46.080 回答
3

“这个视图比设备显示大得多。”

所以你通过移动视图来滚动数据表示?您可能需要考虑使您的视图与显示的大小相同,并使用 CGTranslate 来调整您的 drawRect 函数中的绘图偏移。听起来您正在绘制大量的东西,而 CoreGraphics 无法分辨什么是可见的,什么是不可见的。

如果您缩小视图并插入检查以避免绘制超出视图边界的内容,您将获得更好的绘图性能。

于 2009-12-08T02:52:41.723 回答
1

这是很有可能的,您需要指定需要绘制屏幕的哪些部分,您需要按照此处setNeedsDisplayInRect所述调用并传入一个 CGRect ,这是您希望重绘的区域。

这比重新绘制整个屏幕要快得多,我在一年半前创建的 iPhone 绘图应用程序中遇到了这个问题。

于 2009-12-08T02:30:24.933 回答
0

除了本的建议:

如果您正在滚动数据,请考虑在滚动视图中添加一些较小的视图。这样你大部分时间都不需要重绘,但只有当你的滚动视图的某些区域不再被覆盖时。基本上,如果您的一个子视图完全滚动到视线之外,您会将其移动到可见区域的另一侧并相应地重新绘制它。

在我的应用程序中,我只水平滚动,并且正在使用两个子视图。假设view1在左边,view2在右边。当 view2 滚动到视线之外时,我将它移到 view1 的左侧并相应地重新绘制它。如果用户在同一方向进一步滚动 view1 也会滚动到视线之外,我会将其移动到 view2 的左侧,依此类推。

如果您需要水平和垂直滚动,则需要 4 个视图。

于 2009-12-08T03:03:50.197 回答
0

我知道您可能已经意识到这一点,但是您是否查看过用于数据可视化的Core Plot 框架?我们最近添加了图形的触摸滚动,并且在框架内的内存方面我们试图保持保守。在不了解您的具体情况的情况下,这可能是您可以尝试的。

于 2009-12-08T05:28:24.487 回答