0

我正在开发一个 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 
)}
4

1 回答 1

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];
    }
    

所有这三种情况都可能会纠正您的内存情况(除非您有一些未检测到的保留周期或泄漏)。

于 2013-05-09T13:20:14.337 回答