【问题标题】:NSImage initwithData memory leakNSImage initwithData 内存泄漏
【发布时间】:2020-06-14 10:38:50
【问题描述】:

当我想创建一个 NSImage 对象时,我遇到了内存泄漏。我通过以下方式编译了代码: clang -o test test.m -framework Foundation -fsanitize=leak -framework CoreGraphics -framework AppKit,我用的clang就是这样的: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有内存泄漏。 如果在while循环中运行,内存消耗不断增加。

它适用于@Asperi 提供的答案。但是当我想做更多与NSImage相关的工作时,像这样:这段代码会崩溃,因为CGImageRelease(cgImg);[img release];不能同时启用。但是如果我禁用其中一个,代码不会崩溃,但内存消耗会不断增加。

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

【问题讨论】:

    标签: objective-c memory-leaks nsimage


    【解决方案1】:

    可能会在 SDK 中创建自动释放的对象,因此请尝试使用(对于带有objective-c 对象的此类循环,这始终是一种好习惯)

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

    【讨论】:

    • 这个解决方案有效,但是当我想对 NSImage 对象做更多的事情时,它仍然存在内存泄漏问题。我已经在问题中发布了新代码。
    • @XingweiLin,“错误改变了行为?” )) - 你不应该释放pathcontentcgImg,因为它们是自动释放的。我认为this article 会对你有所帮助
    • 实际上,我不知道为什么在@autoreleasepool{}中,我们仍然需要调用[img release]img对象不会被自动释放吗?而pathcontent 在@autoreleasepool 之外,为什么不应该释放它们。
    • @XingweiLin,您需要熟悉objective-c 内存管理规则(请参阅之前的评论官方Apple 文档中的参考-我不会在这里复制粘贴)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-15
    • 1970-01-01
    • 2011-10-29
    相关资源
    最近更新 更多