xiu*_*ius 15 core-graphics objective-c ios automatic-ref-counting
我最近开始使用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;
}
Run Code Online (Sandbox Code Playgroud)
有没有其他方法不会吃掉这么多内存,或者在使用ARC时代码出了什么问题呢?
发生内存警告+崩溃的另一个地方是任何视图的重绘过多.它不需要很快,只需要很多次.内存堆栈直到它崩溃,我无法找到任何真正的责任.(我可以在VM Tracker中看到不断增长的驻留/脏内存以及Allocations工具中的堆增长)
我的问题主要是:如何找到它为什么会发生?我的理解是,当没有给定对象的所有者时,它会尽快发布.我对代码的检查表明,即使我没有看到任何理由,也没有发布任何对象.我不知道任何保留周期......
我已经阅读了过渡到ARC发行说明,bbum关于堆分析的文章,可能还有十几个.有和没有ARC的堆分析不一样?我似乎无法对其输出做任何有用的事情.
谢谢你的任何想法.
更新:(不要强迫所有人阅读所有评论并履行我的承诺)
通过仔细检查我的代码并添加@autoreleasepool,它有任何意义,内存消耗降低了.最大的问题是UIGraphicsBeginImageContext从后台线程调用.在修复它之后(请参阅@Tammo Freese的答案以获取详细信息),释放很快就会导致应用程序崩溃.
我的第二次崩溃(由许多重绘同一图表引起)CGContextFlush(context)在我的绘图方法结束时添加完全解决了 .对我感到羞耻.
对于试图做类似事情的人来说,这是一个小警告:使用OpenGL.CoreGraphics不足以快速制作大型绘图,特别是在iPad 3上没有.(第一个带有视网膜)
Tam*_*ese 18
回答你的问题:使用ARC识别内存警告和崩溃的问题基本上像以前一样使用手动保留释放(MRR).ARC使用retain,release并且autorelease就像MRR,它只是插入您的通话,并具有一定的优化到位,即使是应该降低在某些情况下,内存消耗.
关于你的问题:
在您发布的仪器的屏幕截图中,可以看到分配峰值.在我到目前为止遇到的大多数情况下,这些尖峰是由自动释放的物体悬挂太久造成的.
你提到过你使用过NSOperationQueue.如果覆盖-[NSOperationQueue main],请确保包含方法的全部内容@autoreleasepool { ... }.自动释放池可能已经到位,但不能保证(即使有一个,也可能比你想象的要长一些).
如果1.没有帮助,并且您有一个处理图像的循环,请将循环的内部部分包裹起来,@autoreleasepool { ... }以便立即清除临时对象.
你提到过你使用过NSOperationQueue.从iOS 4开始,在UIKit中绘制到图形上下文是线程安全的,但如果文档是正确的,UIGraphicsBeginImageContext那么仍然只能在主线程上调用!更新:文档现在声明,自从iOS 4以来,可以从任何线程调用该函数,以下实际上是不必要的!为了安全起见,使用创建上下文CGBitmapContextCreate并检索图像CGBitmapContextCreateImage.这些方面的东西:
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, colorSpace, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
// draw to the context here
CGImageRef newCGImage = CGBitmapContextCreateImage(context);
CGContextRelease(context);
UIImage *result = [UIImage imageWithCGImage:newCGImage scale:scale orientation: UIImageOrientationUp];
CGImageRelease(newCGImage);
return result;
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
10183 次 |
| 最近记录: |