NSImage initwithData утечка памяти - PullRequest
1 голос
/ 02 марта 2020

Когда я хочу создать объект NSImage, я столкнулся с утечкой памяти. Я скомпилировал код следующим образом: clang -o test test.m -framework Foundation -fsanitize=leak -framework CoreGraphics -framework AppKit, использованный мной лязг был таким: gist

// test.m
#include <Foundation/Foundation.h>
#include <Foundation/NSURL.h>
#include <dlfcn.h>
#include <stdint.h>
#include <sys/shm.h>
#include <dirent.h>

#import <Cocoa/Cocoa.h>
#import <ImageIO/ImageIO.h>

int main(int argc, const char * argv[]) {
    if (argc < 2) {
        printf("Usage: %s path/to/image\n", argv[0]);
        return 0;
    }

    NSString* path = [NSString stringWithUTF8String:argv[1]];
    NSData* content = [NSData dataWithContentsOfFile:path];
    while(true) {
        NSImage* img = [[NSImage alloc] initWithData:content];
        [img release];
    }

    [content release];
    [path release];
    return 0;
}

Затем я вызвал его с помощью ./test test.tiff, asan сообщил об ошибке, что initWithData имеет утечку памяти. Если он работает при l oop, потребление памяти продолжает увеличиваться.

Работает с ответом, предоставленным @Asperi. Но когда я хочу сделать больше работ, связанных с NSImage, например: этот код будет обрабатывать sh, потому что CGImageRelease(cgImg); и [img release]; не могут быть включены в это время. Но если я отключу один из них, код не взломает sh, но потребление памяти будет увеличиваться.

#include <Foundation/Foundation.h>
#include <Foundation/NSURL.h>
#include <dlfcn.h>
#include <stdint.h>
#include <sys/shm.h>
#include <dirent.h>

#import <Cocoa/Cocoa.h>
#import <ImageIO/ImageIO.h>

int main(int argc, const char * argv[]) {
    if (argc < 2) {
        printf("Usage: %s path/to/image\n", argv[0]);
        return 0;
    }

    NSString* path = [NSString stringWithUTF8String:argv[1]];
    NSData* content = [NSData dataWithContentsOfFile:path];
    while(true) {
        @autoreleasepool {
            NSImage* img = [[NSImage alloc] initWithData:content];
            NSLog(@"Image @ %p: %@\n", img, img);
            CGImageRef cgImg = [img CGImageForProposedRect:nil context:nil hints:nil];
            if (cgImg) {
                size_t width = CGImageGetWidth(cgImg);
                size_t height = CGImageGetHeight(cgImg);
                CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
                CGContextRef ctx = CGBitmapContextCreate(0, width, height, 8, 0, colorspace, 1);
                CGRect rect = CGRectMake(0, 0, width, height);
                CGContextDrawImage(ctx, rect, cgImg);
                CGColorSpaceRelease(colorspace);
                CGContextRelease(ctx);
                CGImageRelease(cgImg);
            }
            [img release];
        }
    }

    [content release];
    [path release];
    return 0;
}

1 Ответ

1 голос
/ 02 марта 2020

Возможно, в SDK создан объект автоматического освобождения объекта, поэтому попробуйте использовать его (это всегда хорошая практика для таких циклов с объектами - c)

while(true) {
  @autoreleasepool {
      NSImage* img = [[NSImage alloc] initWithData:content];
      [img release];
  }
}
...