CAMetalLayer nextDrawable утечка памяти? - PullRequest
0 голосов
/ 22 декабря 2019

В настоящее время я изучаю утечку памяти в iOS.

У нас есть ViewController и представление для этого контроллера.
ViewController в настоящее время неоднократно выдвигается и выталкивается (для целей отладки).
Представление содержит CAMetalLayer (метод класса layerClass возвращает CAMetalLayer) и CADisplayLink, который вызывает мой метод рендеринга.
Когда я вызываю [metalLayer nextDrawable] в первый раз, приложение выделяет приблизительно 20 МБ. однако, только часть этого выпущена, когда 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];
}
}

enter image description here

мне кажется, что для каждого CAMetalLayer приложение создает IOSurface, но как я могу выпустить их?

диаграмма пошаговая, потому что я жду 2 секунды, прежде чем вывести на экран контроллер вида. «Шаги» появляются, когда я нажимаю контроллер представления.
Я заметил, что поднимается только «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];
}

1 Ответ

0 голосов
/ 22 декабря 2019

Проблема была CADisplayLink.
Вам необходимо использовать -[[CADisplayLink]invalidate], чтобы правильно ее освободить. Недостаточно удалить его из RunLoop вручную.

...