内存警告和崩溃(ARC) - 如何识别它的原因?(Memory warning and crash

2019-06-26 10:11发布

我开始最近使用ARC从那以后,我责备它为每一个存储的问题。 :)也许,你能帮助我更好地理解我在做什么错。

我现在的项目是CoreGraphics在很多 - 图表绘制,景色充满了缩略图等。 我相信,在使用手动内存管理,也许除了几个僵尸就没有问题。但是截至目前,应用程序只需崩溃每次我试图要么创造了很多缩略图或重绘一个比较复杂的图表时。

虽然与仪器剖析我可以看到驻留内存,以及在脏的一个非常高的价值。 堆分析表明相当惊人的不规则成长...

当绘制短短的缩略图,驻留内存增长约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时就不会吃那么多内存或东西真的错了代码中的一些其他的方式?

其中内存警告+碰撞是发生在其他地方的时候有任何视图的太多重绘。 它并不需要是快速的,只是很多次。 内存堆叠起来,直到它崩溃,我无法找到任何东西它真正负责任。 (I可以看到在VM跟踪越来越驻留/脏存储器和在分配器械堆生长)

我的问题主要是:如何找到为什么它甚至发生? 我的理解是,当不存在给定对象没有所有者,它释放尽快。 我的代码检查表明,大量的对象不释放所有,即使我看不出有任何理由要发生。 我不知道任何保留周期...

我已经通过过渡到ARC发布说明,bbum的大约堆分析和可能其他的十几读条。 不同的使用和不使用ARC莫名其妙地堆分析? 我似乎无法做任何事情与它的有用输出 。

谢谢你的任何想法。

更新:(不强制大家阅读所有的意见,并责成我的诺言)

通过我的代码仔细地获取和增加@autoreleasepool,它有什么意义,内存消耗得到了降低。 最大的问题是调用UIGraphicsBeginImageContext从后台线程。 固定之后(见@Tammo弗里兹对细节的答案)释放发生足够很快不会崩溃的应用程序。

我的第二碰撞(由同一图的许多重画),完全通过加入解决CGContextFlush(context)在我的绘制方法的结束。 可耻的是我。


任何人试图做类似的事情一个小警告: 使用OpenGL。 CoreGraphics中不够快的动画大图纸,尤其不能在iPad 3(第一个与视网膜)

Answer 1:

要回答你的问题:识别与记忆警告和崩溃,ARC的问题基本上就像之前手动保留释放(MRR)。 ARC采用retainreleaseautorelease ,就像MRR,它只是插入您的通话,并具有一定的优化到位,即使是应该降低在某些情况下,内存消耗。

关于你的问题:

在你贴仪器屏幕截图 ,有明显的分配尖峰。 在我遇到到目前为止大多数情况下,这些尖峰被自动释放对象游逛过长引起的。

  1. 你提到你使用NSOperationQueue 。 如果重写-[NSOperationQueue main] ,请确保您缠绕法的整个内容@autoreleasepool { ... } 自动释放池可能已经到位,但并不保证(即使有一个,比你认为这可能是周围更长)。

  2. 如果1没有帮助,你有一个循环,处理图像,包裹循环在内部@autoreleasepool { ... }使临时对象立即清理。

  3. 你提到你使用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; 


Answer 2:

所以,什么你在做相对于内存管理(有没有!)看起来不正确的。 不过,你提到使用NSOperationQueue。 这些UIGraphics ...通话将被标记为不是线程安全的,但其他人都表示他们是为iOS 4的的(我无法找到一个明确的答案,但记得,这是真的。

在任何情况下,你不应该调用多个线程,这些类的方法。 您可以创建一个串行调度队列和饲料通过了所有的工作,以确保单线程的使用情况。

现在缺少的,当然这里是你使用后图像做什么。 它可能要在某些方面不是很明显留住他们。 这里有一些技巧:

  • 在任何类中使用大量的图片,添加,用来记录它的名字和一些标识符的dealloc()方法。

  • 你可以尝试将dealloc的增加的UIImage做同样的。

  • 尝试使用尽可能简单的设置来驱动你的应用程序 - 最少的图像等 - 这样你就可以验证的事实,即图像和它们的主人越来越dealloc'd。

  • 当你想确保东西被释放,将伊娃或财产为零

我转换一个100文件项目去年夏天ARC和它的工作完美开箱。 我已经转换几个开源项目,只有一个问题,当我使用不当桥接ARC的为好。 该技术是稳如磐石。



Answer 3:

这不是一个回答你的问题,但我试图解决ARC引入很久以前类似的问题。 最近,我的工作对在内存缓存图像的应用程序和接收内存警告后释放了他们。 这工作得很好,只要我使用以正常速度的应用程序(不疯狂敲击)。 但是,当我开始产生大量的事件和许多图像的开始加载,应用程序没能得到内存警告,它崩溃。

我曾经写过这是按一个按钮就创建后,许多自动释放对象测试应用程序。 我能够挖掘更快(创建对象),比OS管理,以释放内存。 该内存显著时间后慢慢增加,从而,或者干脆利用更大的对象我肯定会导致应用程序崩溃并导致设备重启(看起来真的有效;))。 我检查了使用不幸影响了测试并取得一切较慢的仪器,但我想不使用仪器时,这是真也。

在其他场合,我正在研究一个更大的项目,是相当复杂的,有很多从代码中创建用户界面。 它也有很多的字符串处理,没人照顾的使用隔离 - 有几千当我检查最后一次自动释放呼叫。 所以5分钟这个应用程序的轻微广泛使用后,它崩溃并重启设备。

如果我是正确的,则OS /逻辑负责实际释放内存不够快或者有足够的优先级不高,从当进行大量的内存操作的崩溃保存应用程序。 我从来没有证实这些怀疑,我不知道如何解决其他这个问题不是简单地减少分配的内存。



文章来源: Memory warning and crash (ARC) - how to identify why it's happening?