我的当前项目与CoreGraphics有很多关系 - 图表绘制、缩略图填充视图等等。我认为,如果使用手动内存管理,除了可能会出现一些僵尸进程外,应该不会有问题... 但目前,每当我尝试创建大量缩略图或重新绘制稍微复杂的图表时,应用程序就会崩溃。
在使用Instruments进行分析时,我可以看到驻留内存和脏内存的值非常高。堆分析显示出了相当令人担忧的不规则增长...
当只绘制几个缩略图时,驻留内存会增长约200MB。当所有东西都被绘制完后,内存会回到几乎与绘制前相同的值。然而,对于大量的缩略图,驻留内存中的值高于400 MB,这显然会导致应用程序崩溃。我尝试限制同时绘制的缩略图数量(使用NSOperationQueue和其maxConcurrentOperationCount),但由于释放如此多的内存似乎需要更多的时间,这并没有真正解决问题。
我现在的应用基本上不能像真实数据一样工作,因为有很多复杂的图表=很多缩略图。
每个缩略图都是使用我从这里得到的代码创建的:(UIImage上的类别)
+ (void)beginImageContextWithSize:(CGSize)size
{
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
if ([[UIScreen mainScreen] scale] == 2.0) {
UIGraphicsBeginImageContextWithOptions(size, YES, 2.0);
} else {
UIGraphicsBeginImageContext(size);
}
} else {
UIGraphicsBeginImageContext(size);
}
}
+ (void)endImageContext
{
UIGraphicsEndImageContext();
}
+ (UIImage*)imageFromView:(UIView*)view
{
[self beginImageContextWithSize:[view bounds].size];
BOOL hidden = [view isHidden];
[view setHidden:NO];
[[view layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
[self endImageContext];
[view setHidden:hidden];
return image;
}
+ (UIImage*)imageFromView:(UIView*)view scaledToSize:(CGSize)newSize
{
UIImage *image = [self imageFromView:view];
if ([view bounds].size.width != newSize.width ||
[view bounds].size.height != newSize.height) {
image = [self imageWithImage:image scaledToSize:newSize];
}
return image;
}
+ (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize
{
[self beginImageContextWithSize:newSize];
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
[self endImageContext];
return newImage;
}
有没有其他方法可以不占用太多内存,或者使用ARC时代码出了什么问题?
另一个内存警告和崩溃发生的地方是当任何视图重绘太多次时。它不需要很快,只是很多次。内存堆积直到崩溃,我无法找到真正负责任的东西。(我可以在VM Tracker中看到不断增长的常驻/脏内存和在分配仪器中的堆增长)
我的问题基本上是:如何找出为什么会发生这种情况?我的理解是,当给定对象没有所有者时,它会尽快释放。我检查代码发现,很多对象根本没有被释放,即使我看不到任何原因发生这种情况。我不知道是否存在任何保留周期...
我已经阅读了“过渡到ARC发布说明”、bbum关于堆分析的文章以及可能有十几篇其他文章。有什么区别是使用ARC和不使用ARC进行堆分析吗?我似乎无法对其输出做任何有用的事情。
感谢任何想法。
更新:(为了不强迫每个人都阅读所有评论并遵守我的承诺)
通过仔细检查我的代码并在有意义的地方添加@autoreleasepool,内存消耗得到了降低。最大的问题是从后台线程调用UIGraphicsBeginImageContext。修复后(详见@Tammo Freese的答案),释放发生得足够快,不会导致应用程序崩溃。
我的第二个崩溃(由于多次重绘相同的图表而引起)完全通过在绘图方法末尾添加CGContextFlush(context)解决。我真是太丢人了。
对于任何试图做类似事情的人,有一个小警告:使用OpenGL。 CoreGraphics不足以快速绘制大型动画,尤其是在iPad 3上(第一个带视网膜屏幕的iPad)。
CGContextAddLineToPoint
,CGContextAddRect
等返回空值。我应该释放从CGContextRef context = UIGraphicsGetCurrentContext();
获取的上下文吗?虽然我会研究一下。 - xius