【问题标题】:How to release memory quickly inside receiving method?如何在接收方法中快速释放内存?
【发布时间】:2014-01-05 21:44:39
【问题描述】:

在我的 iPhone 应用程序中,我有一个缓存到磁盘的大图像,我在将图像交给一个对该图像进行大量处理的类之前检索它。接收类只需要简单的图像进行一些初始化,我想尽快释放图像占用的内存,因为图像处理代码非常占用内存,但我不知道如何。

看起来像这样:

// inside viewController
- (void) pressedRender
{
    UIImage *imageToProcess = [[EGOCache globalCache] imageForKey:@"reallyBigImage"];
    UIImage *finalImage = [frameBuffer renderImage:imageToProcess]; 
    // save the image
}


// inside frameBuffer class
- (UIImage *)renderImage:(UIImage *)startingImage
{
    CGContextRef context = CGBitmapCreateContext(....)
    CGContextDrawImage(context, rect, startingImage.CGImage);

    // at this point, I no longer need the image 
    // and would like to release the memory it's taking up

    // lots of image processing/memory usage here...


    // return the processed image
    CGImageRef tmpImage = CGBitmapContextCreateImage(context);
    CGContextRelease(context);
    UIImage *renderedImage = [UIImage imageWithCGImage:tmpImage];
    CGImageRelease(tmpImage);
    return renderedImage;
}

这可能很明显,但我遗漏了一些东西。谢谢。

【问题讨论】:

  • 你试过自动释放池吗?
  • 我查看了自动释放池,但没有看到如何在 CGContextDrawImage 之后立即释放内存。似乎自动释放池会在整个 renderImage 方法完成后释放它......这为时已晚。但话又说回来,我对自动释放池不是很精通。
  • 你肯定需要添加一个CGContextRelease()来释放引用的上下文。
  • 您要释放哪个对象?如果你试图在renderImage 中释放startingImage,你真的不应该因为那个方法不“拥有”那个对象。
  • 我正在尝试在将startingImage 绘制到上下文后释放它。我知道 frameBuffer 不拥有它,但那是我需要释放它的地方。我认为 Rob 的回答可能是最好的方法。

标签: ios objective-c memory image-processing uiimage


【解决方案1】:

@Jonah.at.GoDaddy 走在正确的轨道上,但我会让所有这些更明确,而不是依赖 ARC 优化。 ARC 在调试模式下的攻击性要小得多,因此除非您采取措施,否则在调试时您的内存使用量可能会变得过高。

UIImage *imageToProcess = [[EGOCache globalCache] imageForKey:@"reallyBigImage"];

首先,我假设imageForKey: 本身不缓存任何内容,也不调用imageNamed:(它会缓存内容)。

关键是当你希望内存消失时,你需要将指针置零。如果您将图像从一个地方传递到另一个地方,那将非常困难(Jonah 的解决方案也解决了这个问题)。就个人而言,我可能会做这样的事情来尽可能快地从图像->上下文中获取:

CGContextRef CreateContextForImage(UIImage *image) {
    CGContextRef context = CGBitmapCreateContext(....)
    CGContextDrawImage(context, rect, image.CGImage);
    return context;
}

- (void) pressedRender {

    CGContextRef context = NULL;

    // I'm adding an @autoreleasepool here just in case there are some extra 
    // autoreleases attached by imageForKey: (which it's free to do). It also nicely
    // bounds the references to imageToProcess.
    @autoreleasepool {      
      UIImage *imageToProcess = [[EGOCache globalCache] imageForKey:@"reallyBigImage"];
      context = CreateContextForImage(imageToProcess);
    }
    // The image should be gone now; there is no reference to it in scope.

    UIImage *finalImage = [frameBuffer renderImageForContext:context]; 
    CGContextRelease(context);
    // save the image
}


// inside frameBuffer class
- (UIImage *)renderImageForContext:(CGContextRef)context
{
    // lots of memory usage here...
     return renderedImage;
}

对于调试,您可以通过向其添加关联的观察者来确保 UIImage 真的消失了。请参阅How to enforce using `-retainCount` method and `-dealloc` selector under ARC? 的已接受答案(答案与问题无关;它恰好解决了您可能会发现有用的相同问题)。

【讨论】:

  • 谢谢。这正是我所需要的。
【解决方案2】:

您可以使用相同的方法立即自动释放对象。我认为您需要尝试在一种方法中处理“大图像”过程才能使用@autorelease:

-(void)myMethod{

//do something

@autoreleasepool{
 // do your heavy image processing and free the memory right away
}

//do something
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-04
    • 1970-01-01
    相关资源
    最近更新 更多