我的数据可视化应用程序在重绘期间会产生大量内存消耗峰值(setNeedsDisplay会触发drawRect)。我目前正在重新绘制包含数据图的整个视图。此视图比设备显示大得多。
有没有办法告诉CoreGraphics分配足够的内存来绘制每个元素(每个元素都是一个比设备显示小得多的小矩形块)并在完成后释放内存,而不是我当前的天真方法?
提前致谢。
-Doug
美国东部时间12月8日上午8:28
以下是具有解释性词汇的相关代码。我正在运行使用ObjectAlloc,Memory Monitor和Leaks仪器运行的仪器。我唯一的内存泄漏是由于NSOperationQueue没有释放mems。这是次要的,不相关。
在架构上,应用程序包含一个tableView,其中列出了人类基因组中要检查的有趣位置。当选择表行时,我将数据收集操作排入队列,该操作返回名为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的水平
我正在寻找的解决方案将允许我基本上创建一个水平渲染缓冲区窗口,该窗口是单行对齐对象的高度。我会将其内存渲染分配到其中,然后将其丢弃。我会一遍又一遍地为每一行对齐数据做这件事。
理论上,我可以用这种方法渲染无限量的数据,这当然是最优秀的; - )。
-Doug
答案 0 :(得分:6)
这是 - 我的记忆问题不是那么明显的答案。我会给自己这个,因为我是在苹果开发论坛Rincewind上学到的 - 一位非常有帮助的Apple工程师BTW。
事实证明,通过将大视图切成N个较小的片段并依次渲染到每个片段中,我将产生大约为大视图大小1 / N的存储器尖峰。
因此,对于每个较小的视图:alloc / init,提供我的一部分数据,setNeedsDisplay。冲洗/重复所有N个小视图。
简单,嗯?
在学习之前,我错误地认为setNeedsDisplay:myRect为大视图做了这个。显然不是。
感谢所有建议帮派。
干杯, 道格 @dugla
答案 1 :(得分:3)
“此视图比设备显示大得多。”
所以你通过移动视图来滚动数据表示?您可能需要考虑使视图与显示大小相同,并使用CGTranslate调整drawRect函数中的绘图偏移。这听起来像是在吸引大量的东西,CoreGraphics无法分辨出什么是可见的,什么不是。
如果缩小视图并插入检查以避免绘制超出视图边界的内容,您将获得更好的绘图性能。
答案 2 :(得分:1)
这很可能,您需要指定需要绘制屏幕的哪些部分,您需要按照here所述调用setNeedsDisplayInRect
并传入您希望的CGRect区域重新绘制。
这比重新绘制整个屏幕快得多,我在一年半前创建的iPhone绘图应用程序中遇到了这个问题。
答案 3 :(得分:0)
除了Ben的建议:
如果要滚动数据,请考虑向滚动视图添加一些较小的视图。这样,您不需要在大多数时间重绘,但只有在滚动视图的某些区域不再被覆盖时才需要重绘。基本上,如果您的某个子视图完全滚出视线,则会将其移动到可见区域的另一侧并相应地重绘。
在我的应用程序中,我只是水平滚动,并使用两个子视图。假设view1在左边,view2在右边。当view2滚动到视线之外时,我将其移动到view1的左侧并相应地重绘它。如果用户在同一方向上进一步滚动,view1也会滚动到视线之外,我会将它移到view2的左侧,依此类推。
如果您需要水平和垂直滚动,则需要4个视图。
答案 4 :(得分:0)
我知道您可能已经意识到了这一点,但您是否看过Core Plot framework数据可视化?我们最近添加了图形的触摸滚动,我们试图在框架内的内存方面保守。如果不了解您的具体情况,可能会尝试这样做。