4

为了方便起见,我用一些工作代码编辑了上一篇文章。

以下代码(ARC'ed)似乎会泄漏,并且会在运行一小段时间后使 sim 卡或设备崩溃:

#define kROWS 100
#define kCols 34

void run();

static ViewController *instance;

@interface ViewController ()
@property (nonatomic, strong) NSMutableArray *nsBackColor;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.nsBackColor = [NSMutableArray arrayWithCapacity:1];
    instance = self;

    // set up a '2D array'
    for (int x = 0; x < kROWS; x++) {
        [self.nsBackColor addObject:[NSMutableArray arrayWithCapacity:1]];
        for (int y = 0; y < kCols; y++) {
            [[self.nsBackColor objectAtIndex:x] addObject:[UIColor whiteColor]];
        }
    }

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        run();
    });
}

- (void)plotColor:(UIColor *)color atX:(short)x andY:(short)y {
    [[self.nsBackColor objectAtIndex:x] replaceObjectAtIndex:y withObject:color];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

void plot(short xLoc, short yLoc,
              short backRed, short backGreen, short backBlue) {

    @autoreleasepool {
        [instance plotColor:[UIColor colorWithRed:((float)backRed/100)
                                            green:((float)backGreen/100)
                                             blue:((float)backBlue/100)
                                            alpha:(float)1]
                        atX:xLoc andY:yLoc];
    }
}

void run() {
    short x = 0;
    short y = 0;
    short backRed = 0;
    short backGreen = 0;
    short backBlue = 0;

    while (true) {
        x++;
        if (x >= kROWS) {
            x = 0;
        }

        y++;
        if (y >= kCols) {
            y = 0;
        }

        backRed = arc4random() % 255;
        backBlue = arc4random() % 255;
        backGreen = arc4random() % 255;

        plot(x, y, backRed, backGreen, backBlue);

        usleep(1000);
    }
}

如果我让它在设备或模拟器上运行足够长的时间(几分钟),我将收到 mmap malloc 错误(sim)或内存警告(设备)并崩溃。

通过 Instruments Allocations 我可以看到 +[UIColor colorWithRed:green:blue:alpha:] 开始膨胀,直到最终撞到内存墙。

我可以将 UIColor 分配给一个属性(直接或通过复制),比如 self.myColor = color,并且没有这样的泄漏。

我也可以这样做:

[[self.nsBackColor objectAtIndex:x] replaceObjectAtIndex:y withObject:[self description]];

我得到了同样的泄漏。

在我看来,在数组中替换的对象(是的,这最初是作为 2D c 数组开始的,但我认为这是问题所在)永远丢失并泄漏并且没有正确释放。

这将是运行一小段时间后的 Instruments->Allocations:

仪器

任何帮助将不胜感激,并且可以提供更多信息。

4

1 回答 1

0

正在发生的事情是您在每次迭代时都创建了一个自动释放池。因此,每次都会使用新的自动释放池运行以下行:

[[self.nsBackColor objectAtIndex:x] replaceObjectAtIndex:y withObject:color];

因此color将其在本地池中的引用计数增加一,同时[[self.nsBackColor objectAtIndex:x] objectAtIndex:y]将其在本地池中的引用计数减少一。但这里有一个问题:该项目color在上一个迭代中,它的引用计数由您之前排空/释放的上一个池管理。

所以应该发生的是,在上一次迭代中释放了上一个池,该对象被释放了。它的引用计数为 2(一个用于[UIColor colorWith...],一个用于添加到数组中),因此它应该在池耗尽后立即收到 2 个释放消息,并且指针 in[[self.nsBackColor objectAtIndex:x] objectAtIndex:y]应该悬空,直到您在当前迭代中将其替换为指向的指针color

显然,这并没有完全按照它应该的方式发生,或者我理解的方式。但是,该@autoreleasepool {}指令显然是错误的。它应该在while (true)循环周围,或者完全删除以支持线程池。

于 2013-02-27T10:03:33.410 回答