内存警告和崩溃(ARC) - 如何识别它发生的原因? [英] Memory warning and crash (ARC) - how to identify why it's happening?

查看:183
本文介绍了内存警告和崩溃(ARC) - 如何识别它发生的原因?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近开始使用ARC,从那以后我就把它归咎于每一个内存问题。 :)也许,你可以帮助我更好地理解我做错了什么。

I've started to use the ARC recently and since then I blame it for every single memory problem. :) Perhaps, you could help me better understand what I'm doing wrong.

我目前的项目是关于CoreGraphics的 - 图表绘图,填充缩略图的视图等等上。我相信在使用手动内存管理时没有问题,除了一些僵尸......但截至目前,每次我尝试创建大量缩略图或重绘更复杂的图表时应用程序都会崩溃。

My current project is about CoreGraphics a lot - charts drawing, views filled with thumbnails and so on. I believe there would be no problem while using manual memory management, except maybe a few zombies... But as of now, application simply crashes every time I try to either create a lot of thumbnails or redraw a bit more complicated chart.

使用Instruments进行分析时,我可以看到常驻内存和脏内存中的值非常高。堆分析显示相当惊人的不规则增长...

While profiling with Instruments I can see an awfully high value in resident memory as well as in the dirty one. Heap analysis shows rather alarming irregular grow...

当仅绘制几个缩略图时,驻留内存增长约200 MB。绘制完所有内容后,内存会回落到几乎与绘图前相同的值。但是,有很多缩略图,驻留内存中的值高于 400 MB ,这显然会导致应用程序崩溃。我试图限制同时绘制的缩略图数量(NSOperationQueue及其maxConcurrentOperationCount),但由于释放这么多内存似乎需要花费更多时间,所以它并没有真正解决问题。

When drawing just a few thumbnails, resident memory grows for about 200 MB. When everything is drawn, memory drops back on almost the same value as before drawing. However, with a lot of thumbnails, a value in resident memory is higher than 400 MB and that obviously crashes the app. I've tried to limit number of thumbnails drawn at the same time (NSOperationQueue and its maxConcurrentOperationCount), but as releasing so much memory seems to take a bit more time, it didn't really solve the issue.

现在我的应用程序基本上不起作用,因为真实数据适用于许多复杂的图表=很多缩略图。

Right now my app basically doesn't work as the real data works with a lot of complicated charts = lot of thumbnails.

每一个缩略图是用我从这里得到的代码创建的:( UIImage上的类别)

Every thumbnail is created with this code I got from around here: (category on 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时代码确实出错?

Is there some other way which wouldn't eat so much memory or is something really wrong with the code when using ARC?

发生内存警告+崩溃的另一个地方是任何视图重绘过多。它不需要很快,只需要很多次。内存堆积直到它崩溃,我无法找到任何真正的责任。 (我可以看到VM Tracker中的驻留/脏内存不断增长以及Allocations工具中的堆增长)

The other place where memory warning + crash is happening is when there is too much redrawing of any view. It doesn't need to be quick, just many times. Memory stacks up until it crashes and I'm not able to find anything really responsible for it. (I can see a growing resident/dirty memory in VM Tracker and a heap growth in Allocations instrument)

我的问题基本上是:如何找到它为什么会发生?我的理解是,当没有给定对象的所有者时,它会尽快发布。我对代码的检查表明,即使我没有看到任何理由,也没有发布任何对象。我不知道任何保留周期......

My question basically is: how to find why it is even happening? My understanding is when there is no owner for given object, it's released ASAP. My inspection of code suggests a lot of objects are not released at all even though I don't see any reason for it to happen. I don't know about any retain cycles...

我已经阅读了过渡到ARC发行说明,bbum关于堆分析的文章,可能还有十几个其他人。有和没有ARC的堆分析不一样?我似乎无法对其输出做任何有用的事情。

I've read through the Transitioning to ARC Release Notes, bbum's article about heap analysis and probably a dozen of others. Differs somehow heap analysis with and without ARC? I can't seem to do anything useful with its output.

感谢您的任何想法。

更新:(不强迫所有人阅读所有评论并履行我的承诺)

UPDATE: (to not force everybody read all the comments and to hold my promise)

通过仔细检查我的代码并添加@autoreleasepool,它有任何意义,内存消耗降低了。最大的问题是从后台线程调用 UIGraphicsBeginImageContext 。修复后(请参阅@Tammo Freese的答案了解详细信息),释放很快就会导致应用程序崩溃。

By carefully getting through my code and adding @autoreleasepool, where it had any sense, memory consumption got lowered. The biggest problem was calling UIGraphicsBeginImageContext from background thread. After fixing it (see @Tammo Freese's answer for details) deallocation occurred soon enough to not crash an app.

我的第二次崩溃(由多次重绘同一图表引起) ,在我的绘图方法结束时添加 CGContextFlush(context)完全解决了。对我感到羞耻。

My second crash (caused by many redrawing of the same chart), was completely solved by adding CGContextFlush(context) at the end of my drawing method. Shame on me.

对于任何尝试做类似事情的人来说,这是一个小警告:使用OpenGL。 CoreGraphics不够快,不能用于动画大图,特别是在iPad 3上没有。(第一个带有视网膜)

A small warning for anyone trying to do something similar: use OpenGL. CoreGraphics is not quick enough for animating big drawings, especially not on an iPad 3. (first one with retina)

推荐答案

回答你的问题:使用ARC识别内存警告和崩溃的问题基本上与之前的手动保留释放(MRR)一样。 ARC使用保留发布 autorelease 就像MRR一样它只为你插入调用,并且有一些优化,甚至可以在某些情况下降低内存消耗。

To answer your question: Identifying problems with memory warnings and crashes with ARC basically works like before with manual retain-release (MRR). ARC uses retain, release and autorelease just like MRR, it only inserts the calls for you, and has some optimizations in place that should even lower the memory consumption in some cases.

关于你的问题:

您发布的乐器的屏幕截图中,可见分配峰值。在我到目前为止遇到的大多数情况下,这些尖峰是由自动释放的物体悬挂太久造成的。

In the screenshot of Instruments you posted, there are allocation spikes visible. In most cases I encountered so far, these spikes were caused by autoreleased objects hanging around too long.


  1. 你提到你使用了 NSOperationQueue 。如果覆盖 - [NSOperationQueue main] ,请确保将该方法的全部内容包装在 @autoreleasepool {...} 。自动释放池可能已经到位,但不能保证(即使有一个,也可能比你想象的要长一些)。

  1. You mentioned that you use NSOperationQueue. If you override -[NSOperationQueue main], make sure that you wrap the whole content of the method in @autoreleasepool { ... }. An autorelease pool may already be in place, but it is not guaranteed (and even if there is one, it may be around for longer than you think).

如果1.没有帮助并且您有一个处理图像的循环,请将循环的内部部分包装在 @autoreleasepool {...} 中,以便临时对象是立即清理。

If 1. has not helped and you have a loop that processes the images, wrap the inner part of the loop in @autoreleasepool { ... } so that temporary objects are cleaned up immediately.

您提到您使用 NSOperationQueue 。从iOS 4开始,在UIKit中绘制到图形上下文是线程安全的,但如果文档是正确的, UIGraphicsBeginImageContext 仍应仅在主线程上调用! 更新:文档现在声明,从iOS 4开始,可以从任何线程调用该函数,实际上不需要以下内容!为了安全起见,请使用 CGBitmapContextCreate 并使用 CGBitmapContextCreateImage 检索图像。这些内容:

You mentioned that you use NSOperationQueue. Since iOS 4, drawing to a graphics context in UIKit is thread-safe, but if the documentation is right, UIGraphicsBeginImageContext should still only be called on the main thread! Update: The docs now state that since iOS 4, the function can be called from any thread, to the following is actually unnecessary! To be on the safe side, create the context with CGBitmapContextCreate and retrieve the image with CGBitmapContextCreateImage. Something along these lines:

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;


这篇关于内存警告和崩溃(ARC) - 如何识别它发生的原因?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆