在设备上运行app时“收到内存警告”

时间:2013-05-09 06:09:23

标签: ios image uiimageview uiimage

我正在开发iPhone视频解码器应用程序。我需要为每个帧转换原始像素数据并在屏幕上连续渲染(因此形成一个视频)。下面的功能是在屏幕上呈现每个帧的功能。

   - (void)drawBufferWidth:(int)width height:(int)height pixels:(unsigned char*)pixels
    {

         CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

         CGContextRef gtx = CGBitmapContextCreate(pixels, width, height, BitsPerComponent, BytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
         CGColorSpaceRelease(colorSpace);   

         myimage = CGBitmapContextCreateImage(gtx); //myimage is of type CGImageRef
         CGContextRelease(gtx);

         img.image = [UIImage imageWithCGImage:myimage]; //img is of type UIImageView
         [CATransaction flush];
         CGImageRelease(myimage);

         myimage = Nil;
    }

代码在模拟器上运行得非常好。当我在设备上运行它时,它显示几帧,给出“已接收内存警告”并崩溃。

我无法弄清楚问题出在哪里。我没有正确地解除分配,或者即使我正在发布图像,它仍然存在于内存中,从而占用了内存?

请帮忙!

提前致谢。

编辑:

Xcode组织者说:

hevcd[665] has active assertions beyond permitted time: 
{(
    <SBProcessAssertion: 0x11aacf70> identifier: Suspending process: hevcd[665] permittedBackgroundDuration: 10.000000 reason: suspend owner pid:565 preventSuspend  preventThrottleDownCPU  preventThrottleDownUI 
)}

1 个答案:

答案 0 :(得分:0)

有几点意见:

  1. 让我们假设你有一个for循环:

    for (i = start; i < end; i++)
    {
        // doing lots of memory intensive stuff
    }
    

    您必须认识到,在此循环完成并刷新自动释放池之前,在此循环期间自动释放的任何内存都不会实际返回到操作系统。在进行内存密集型操作时,理论上可以这样做:

    for (i = start; i < end; i++)
    {
        @autorelease {
            // doing lots of memory intensive stuff
        }
    }
    

    这样,您就可以手动创建一个新的自动释放池,该池将以更高的频率刷新。

  2. 话虽如此,你真的不应该做一些不会回到操作系统的延长任务(至少在主线程上,因为你正在做UI的东西,你必须这样做主线程)。比执行一些延长的for循环更好的模型是让操作系统定期调用您的代码。然后标准自动释放池将完成它的工作,你应该没事。你可以像这样创建一个计时器:

    - (void)startTimer
    {
        self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1
                                                      target:self
                                                    selector:@selector(handleTimer:)
                                                    userInfo:nil
                                                     repeats:YES];
    }
    

    然后你有一个处理计时器的例程:

    - (void)handleTimer:(NSTimer *)timer
    {
        // do what you need here
    }
    

    确保关闭计时器(例如,当视图消失时),或者当此视图控制器被解除时,它将不会被释放,因为计时器将保持其对它的强引用,并且您将拥有一个保留周期(或强参考周期),你会泄漏内存。

    - (void)viewWillDisappear:(BOOL)animated
    {
        [self.timer invalidate];
    }
    
  3. 您也可以使用CADisplayLink实现类似的功能。您可以创建显示链接:

    - (void)startDisplayLink
    {
        self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
        [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    }
    
    - (void)handleDisplayLink:(CADisplayLink *)displayLink
    {
        // do what you need here
    }
    

    再一次,你要确保在完成后停止它:

    - (void)viewWillDisappear:(BOOL)animated
    {
        [self.displayLink invalidate];
    }
    
  4. 所有这三种情况都可能会纠正您的记忆情况(除非您有一些未检测到的保留周期或泄漏)。