0

http://i46.tinypic.com/2nquzag.png

我有一个应用程序可以在很长的计算过程中创建和释放数百万个 NSNumber。我将@autoreleasepools 与创建和处理这些对象的各种循环一起使用。正如您在仪器屏幕上看到的那样,我只有 10656 个活动 CFNumber,但此时应用程序由于无法为更多对象分配内存而崩溃。有超过 5700 万个 CFNumber 处于“临时”状态。这是否意味着他们被释放了?为什么 malloc 还不使用这些内存位置?

我已经包含了我正在使用的代码的模型。运行 testProbabilities 方法,它将每 10000 次迭代计数一次。在分配错误之前,我使用此代码进行了多达 790000 次迭代。然而 Instruments 对我来说看起来不错。

@implementation MMTest

NSMutableSet *predictedSet;


-(NSMutableArray *)calculateCDF {

//// NORMALIZE PROBABILITIES ////

float probabilitySum = 0;
float runningCDFTotal = 0;
float normaledProbability = 0;

@autoreleasepool {

    NSMutableArray *CDF = [[NSMutableArray alloc] init];

    probabilitySum = 4.5; ////This is just a placholder for additive iteration of an array which creates this sum.

    //// CREATE CDF ////

    int x;

    for (x=0; x<50; x++) {

        normaledProbability = .2/probabilitySum;////This is placeholder for calculation on same array as above.
        runningCDFTotal += normaledProbability;

        [CDF addObject:[NSNumber numberWithFloat:runningCDFTotal]];

    }

    return CDF;

}

}

-(NSMutableSet *)generateNumbers {

@autoreleasepool {

    int x;
    double r = 0;

    if (!predictedSet) {
        predictedSet = [[NSMutableSet alloc] init];
    }

    else {
        [predictedSet removeAllObjects];
    }

    for (x=0; x<5;) {

        r = arc4random_uniform(1000)/1000;////I'm actually using SFMT here instead.
        int num = 0;
        __weak id CDF = [self calculateCDF];


        if (r <= [[CDF objectAtIndex:[CDF count]-1] floatValue]) {

            for (NSNumber *cdf in CDF) {

                if (r <= [cdf floatValue]) {

                    num = [CDF indexOfObject:cdf]+1;

                    [predictedSet addObject:[NSNumber numberWithInt:num]];

                    x++;

                    break;


                }

            }

        }

    }

    return predictedSet;

}

}

-(void)testProbability {

int x = 0;
BOOL nextSetFound = NO;
NSSet *nextSet = [[NSSet alloc] initWithObjects:
                  [NSNumber numberWithInt:1],
                  [NSNumber numberWithInt:2],
                  [NSNumber numberWithInt:3],
                  [NSNumber numberWithInt:4],
                  [NSNumber numberWithInt:5],
                  nil];

while (nextSetFound == NO) {

    @autoreleasepool {

        __weak id newSet = [self generateNumbers];

        x++;

        if ([nextSet isSubsetOfSet:newSet]) {

            nextSetFound = YES;
            NSLog(@"%@", newSet);

        }   

        if (fmod (x,10000) == 0) {
            NSLog(@"%i", x);

        }

    }

}

NSLog(@"%i", x);

}

@end
4

2 回答 2

1

我错了还是你没有在任何地方发布CDF?这样,您CDF每次调用时都会泄漏calculateCDF

尝试这个:

id CDF = [self calculateCDF];

代替

 __weak id CDF = [self calculateCDF];

id newSet = [self generateNumbers];

代替

__weak id newSet = [self generateNumbers];

指定weak将使对象不属于newSetARC,因此不会被 ARC 自动释放。

另一方面,Apple明确反对使用__weak堆栈变量

在堆栈上使用 __weak 变量时要小心。考虑以下示例:

       NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];
       NSLog(@"string: %@", string);

虽然在初始赋值后使用了字符串,但在赋值时并没有其他对字符串对象的强引用;因此,它立即被解除分配。日志语句显示该字符串具有空值。(例如,如果使用 .,您将看不到效果NSString * __weak string = [[NSString alloc] initWithString:@"First Name"]。在这种情况下,initWithString:只返回从未释放的字符串常量。)

据我了解这一段,您要么立即解除分配,要么发生内存泄漏。

我在 iOS 4.3 iPhone 上尝试了您的代码(删除了 __weak),它在仪器下显示了平坦的“物理空闲内存”。

旧答案:

棘手的事情autorelease是自动释放池在不可预知的时间被耗尽(通常在应用程序执行运行循环时)。这与使用release的不同之处在于它在您完成对象的时刻和内存被释放的时刻之间增加了一些延迟。

如果你将这个小延迟(就像系统的惯性autorelease)乘以自动释放对象的数量,这可能会导致内存使用高峰。如果 iOS 在其中一个峰值期间检查内存使用情况,并且您的应用程序无法对随之而来的内存警告做出正确反应,那么您的应用程序将被终止。

另一方面,如果您分配了一个释放池,并且它在运行周期的同一步骤中变得很大,这也可能导致过多的内存使用。

您提供的代码细节很少,所以我不能更准确;无论如何release,如果可能的话,我会尝试使用明确的对象。这将摆脱上述两个问题。或者您可以尝试处理较小的自动释放池(并且您将解决第二种问题)...

我还建议你在 Instruments 中添加一个内存监视器,这样你就会看到系统释放内存的速度有多快。

PS:现在,你所附的图片让我印象深刻的是分配图是绝对平坦的:没有分配,没有释放。我希望内存会上下波动(根据我的经验,这是一个健康的 iOS 应用程序的标志)。

于 2012-07-01T06:59:36.670 回答
0

不知道究竟是为什么,但上面这个确切的代码现在可以正常工作了。在测试各种修改的过程中,我在 Xcode 中启用和禁用了 Guard Malloc 和 Malloc Stack Logging。突然间,我的修改版本开始运行,没有崩溃。然后我再次尝试了这个原始版本,现在它运行良好而没有崩溃。这没有任何意义,但我很高兴它正在工作。

@sergio:我想至少为您提供很多帮助和建议以进一步优化此代码提供很多帮助和建议,但我没有足够高的声誉。谢谢您的帮助。我很感激。

于 2012-07-07T11:49:20.050 回答