CAMetalLayer nextDrawable 内存泄漏?
CAMetalLayer nextDrawable memory leak?
我目前正在调查 iOS 中的内存泄漏。
我们有一个 ViewController 和该控制器的视图。
ViewController 当前被重复推送和弹出(用于调试目的)。
该视图包含一个 CAMetalLayer
(class 方法 layerClass
returns CAMetalLayer
)和一个调用我的渲染方法的 CADisplayLink
。
当我第一次调用 [metalLayer nextDrawable]
时,应用程序分配了大约 20MB。
但是,当 ViewController 弹出时,只有一小部分被释放!
我 100% 确定我没有保留周期或任何东西。
这是我的渲染初始化代码:
-(void)initializeRendering {
@autoreleasepool {
id<MTLDevice> device = [[MetalRenderingSession sharedInstance] renderDevice];
[self setCommandQueue:[device newCommandQueue]];
CAMetalLayer* layer = static_cast<CAMetalLayer*>([self layer]);
layer.device = device;
layer.pixelFormat = MTLPixelFormatRGBA16Float;
layer.framebufferOnly = true;
layer.maximumDrawableCount = 2;
layer.contentsScale = [self contentScaleFactor];
[self setMetalLayer:layer];
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
MTLTextureDescriptor* depthTextureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatDepth32Float
width:static_cast<NSUInteger>(screenSize.width) height:static_cast<NSUInteger>(screenSize.height) mipmapped:NO];
[depthTextureDescriptor setUsage:MTLTextureUsageRenderTarget];
id<MTLTexture> depthTexture = [device newTextureWithDescriptor:depthTextureDescriptor];
[self setTextureDepth:depthTexture];
[self updateOrientation:[[UIApplication sharedApplication] statusBarOrientation] size:[self frame].size];
CADisplayLink* renderLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(render)];
[renderLink setPreferredFramesPerSecond:30];
[self setDisplayLink:renderLink];
[renderLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}
}
这是我的实际渲染代码:
-(void)render {
@autoreleasepool {
dispatch_semaphore_wait([self renderCommandExecuting], DISPATCH_TIME_FOREVER);
id<MTLCommandBuffer> commandBuffer = [[self commandQueue] commandBuffer];
[[self commandQueue] insertDebugCaptureBoundary];
//commenting next line and lines that use drawable makes memory leak disappear?
id<CAMetalDrawable> drawable = [[self metalLayer] nextDrawable];
id<MTLRenderCommandEncoder> encoder = [self createCommandEncoderfromCommandBuffer:commandBuffer andDrawable:drawable];
//creating ViewPort here
[encoder setViewport:viewport];
//doing rendering here, but for debugging purpoeses i disabled rendering
[encoder endEncoding];
[commandBuffer presentDrawable:drawable];
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> o) {
dispatch_semaphore_signal([self renderCommandExecuting]);
}];
[commandBuffer commit];
[commandBuffer waitUntilCompleted];
}
}
对我来说,似乎每个 CAMetalLayer
,该应用都会创建一个 IOSurface
,但我怎样才能释放这些?
图表是阶梯式的,因为我在弹出视图控制器之前等待了 2 秒。
"steps" 当我按下视图控制器时出现。
我注意到只有 "VM:IOSurface" 爬上去,其余的保持不变。
这是我的清理代码(在视图中,从 viewWillDisappear
调用):
-(void)stop {
[[self displayLink] setPaused:YES];
[[self displayLink] removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
//those are 4*4 float arrays, they are allocated in the view's init
free([self projectionMatrix]);
free([self viewMatrix]);
free([self modelMatrix]);
[self setCommandQueue:nil];
[self setMetalLayer:nil];
[self setTextureDepth:nil];
[self setRenderCommandExecuting:nil];
}
问题是 CADisplayLink
。
您需要使用 -[[CADisplayLink]invalidate]
才能正确释放它。
手动将其从 RunLoop 中移除是不够的。
我目前正在调查 iOS 中的内存泄漏。
我们有一个 ViewController 和该控制器的视图。
ViewController 当前被重复推送和弹出(用于调试目的)。
该视图包含一个 CAMetalLayer
(class 方法 layerClass
returns CAMetalLayer
)和一个调用我的渲染方法的 CADisplayLink
。
当我第一次调用 [metalLayer nextDrawable]
时,应用程序分配了大约 20MB。
但是,当 ViewController 弹出时,只有一小部分被释放!
我 100% 确定我没有保留周期或任何东西。
这是我的渲染初始化代码:
-(void)initializeRendering {
@autoreleasepool {
id<MTLDevice> device = [[MetalRenderingSession sharedInstance] renderDevice];
[self setCommandQueue:[device newCommandQueue]];
CAMetalLayer* layer = static_cast<CAMetalLayer*>([self layer]);
layer.device = device;
layer.pixelFormat = MTLPixelFormatRGBA16Float;
layer.framebufferOnly = true;
layer.maximumDrawableCount = 2;
layer.contentsScale = [self contentScaleFactor];
[self setMetalLayer:layer];
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
MTLTextureDescriptor* depthTextureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatDepth32Float
width:static_cast<NSUInteger>(screenSize.width) height:static_cast<NSUInteger>(screenSize.height) mipmapped:NO];
[depthTextureDescriptor setUsage:MTLTextureUsageRenderTarget];
id<MTLTexture> depthTexture = [device newTextureWithDescriptor:depthTextureDescriptor];
[self setTextureDepth:depthTexture];
[self updateOrientation:[[UIApplication sharedApplication] statusBarOrientation] size:[self frame].size];
CADisplayLink* renderLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(render)];
[renderLink setPreferredFramesPerSecond:30];
[self setDisplayLink:renderLink];
[renderLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}
}
这是我的实际渲染代码:
-(void)render {
@autoreleasepool {
dispatch_semaphore_wait([self renderCommandExecuting], DISPATCH_TIME_FOREVER);
id<MTLCommandBuffer> commandBuffer = [[self commandQueue] commandBuffer];
[[self commandQueue] insertDebugCaptureBoundary];
//commenting next line and lines that use drawable makes memory leak disappear?
id<CAMetalDrawable> drawable = [[self metalLayer] nextDrawable];
id<MTLRenderCommandEncoder> encoder = [self createCommandEncoderfromCommandBuffer:commandBuffer andDrawable:drawable];
//creating ViewPort here
[encoder setViewport:viewport];
//doing rendering here, but for debugging purpoeses i disabled rendering
[encoder endEncoding];
[commandBuffer presentDrawable:drawable];
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> o) {
dispatch_semaphore_signal([self renderCommandExecuting]);
}];
[commandBuffer commit];
[commandBuffer waitUntilCompleted];
}
}
对我来说,似乎每个 CAMetalLayer
,该应用都会创建一个 IOSurface
,但我怎样才能释放这些?
图表是阶梯式的,因为我在弹出视图控制器之前等待了 2 秒。
"steps" 当我按下视图控制器时出现。
我注意到只有 "VM:IOSurface" 爬上去,其余的保持不变。
这是我的清理代码(在视图中,从 viewWillDisappear
调用):
-(void)stop {
[[self displayLink] setPaused:YES];
[[self displayLink] removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
//those are 4*4 float arrays, they are allocated in the view's init
free([self projectionMatrix]);
free([self viewMatrix]);
free([self modelMatrix]);
[self setCommandQueue:nil];
[self setMetalLayer:nil];
[self setTextureDepth:nil];
[self setRenderCommandExecuting:nil];
}
问题是 CADisplayLink
。
您需要使用 -[[CADisplayLink]invalidate]
才能正确释放它。
手动将其从 RunLoop 中移除是不够的。