我最近开始使用 ARC,从那以后我把每一个内存问题都归咎于它。:) 也许,你可以帮助我更好地理解我做错了什么。
我目前的项目与 CoreGraphics 有关 - 图表绘制、带有缩略图的视图等等。我相信使用手动内存管理不会有问题,除了一些僵尸......但到目前为止,每次我尝试创建大量缩略图或重绘更复杂的图表时,应用程序都会崩溃。
在使用 Instruments 进行分析时,我可以在常驻内存和脏内存中看到非常高的价值。堆分析显示相当惊人的不规则增长......
仅绘制几个缩略图时,常驻内存会增长约 200 MB。绘制完所有内容后,内存会回落到与绘制前几乎相同的值。但是,对于大量缩略图,常驻内存中的值高于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 中看到不断增长的常驻/脏内存和在 Allocations 工具中的堆增长)
我的问题基本上是:如何找到它为什么会发生?我的理解是当给定对象没有所有者时,它会尽快发布。我对代码的检查表明,许多对象根本没有释放,即使我看不出有任何原因发生。我不知道任何保留周期...
我已经阅读了 Transitioning to ARC Release Notes、bbum 的关于堆分析的文章以及可能还有其他十几篇文章。使用和不使用 ARC 的堆分析有何不同?我似乎无法对它的输出做任何有用的事情。
谢谢你的任何想法。
更新:(不强迫每个人阅读所有评论并遵守我的承诺)
通过仔细检查我的代码并添加@autoreleasepool,它有任何意义,内存消耗降低了。UIGraphicsBeginImageContext
最大的问题是从后台线程调用。修复后(有关详细信息,请参阅@Tammo Freese 的答案)释放很快就会发生,不会导致应用程序崩溃。
我的第二次崩溃(由多次重绘同一图表引起)完全通过 CGContextFlush(context)
在我的绘图方法末尾添加来解决。真丢人。
对任何尝试做类似事情的人的一个小警告:使用 OpenGL。CoreGraphics 对大型绘图的动画制作速度不够快,尤其是在 iPad 3 上。(第一个带有视网膜的)