我正在开发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
)}
答案 0 :(得分:0)
有几点意见:
让我们假设你有一个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
}
}
这样,您就可以手动创建一个新的自动释放池,该池将以更高的频率刷新。
话虽如此,你真的不应该做一些不会回到操作系统的延长任务(至少在主线程上,因为你正在做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];
}
您也可以使用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];
}
所有这三种情况都可能会纠正您的记忆情况(除非您有一些未检测到的保留周期或泄漏)。