iOS内存无法分配

时间:2013-05-22 13:02:29

标签: ios objective-c

我正在ARC自动转换项目中工作。

我有一个存储在NSString *_documentDataString

中的大文本文件(14MB)的内容

现在我有了这个循环:

- (void)scanParts
{
    NSString *boundary = [boundaryPrefix stringByAppendingString:_header.boundary];

    NSMutableArray *parts = [NSMutableArray array];

    NSInteger currentLocation = [_documentDataString rangeOfString:boundary].location;

    BOOL reachedTheEnd = NO;
    while(!reachedTheEnd)
    {
        NSInteger nextBoundaryLocation = [[_documentDataString substringFromIndex:currentLocation + 1]
                                          rangeOfString:boundary].location;

        if(nextBoundaryLocation == NSNotFound)
        {
            reachedTheEnd = YES;
        }
        else
        {
            nextBoundaryLocation += currentLocation + 1;

            //[parts addObject:[_documentDataString substringWithRange:
              //                NSMakeRange(currentLocation, nextBoundaryLocation - currentLocation)]];

            currentLocation = nextBoundaryLocation;
        }
    }
}

但是,我开始收到这些错误:

 malloc: *** mmap(size=6496256) failed (error code=12)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug

出了什么问题?

我在运行此循环时甚至开始出现此错误:

while(true)
{
    NSInteger nextBoundaryLocation = [[_documentDataString substringFromIndex:currentLocation + 1]
                                          rangeOfString:boundary].location;
}

3 个答案:

答案 0 :(得分:5)

中的substringFromIndex:
NSInteger nextBoundaryLocation = [[_documentDataString substringFromIndex:currentLocation + 1]
                                      rangeOfString:boundary].location;

创建一个(临时的,自动释放的)子字符串,该子字符串仅在当前时被释放 autoreleasepool被销毁(例如,当程序控制返回主事件循环时)。

您可以用

替换该代码
NSInteger nextBoundaryLocation = [_documentDataString rangeOfString:boundary
             options:0
               range:NSMakeRange(currentLocation + 1, [_documentDataString length] - (currentLocation + 1))].location;

(希望)避免创建临时字符串。请注意,nextBoundaryLocation然后相对于字符串的开头,所以

nextBoundaryLocation += currentLocation + 1;

不再需要了。

或者,你可以简单地用

替换完整的循环
NSArray *parts = [_documentDataString componentsSeparatedByString:boundary];

答案 1 :(得分:0)

看起来文档太大而无法像通常使用(合理)常规大小的字符串那样操作它,原因是在字符串对象的内存分配过程中出现错误。

对于您的特定情况,您可能需要使用NSInputStream,基本上可以逐字节而不是一次性读取文件的数据。

查看以下问题Objective-C: Reading a file line by line

简而言之,根据文档,您需要执行以下操作:

首先打开文件

- (void)setUpStreamForFile:(NSString *)path {
    // iStream is NSInputStream instance variable
    iStream = [[NSInputStream alloc] initWithFileAtPath:path];
    [iStream setDelegate:self];
    [iStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
        forMode:NSDefaultRunLoopMode];
    [iStream open];
}

编写代码以处理流中有更多可用字节时的操作(虽然它不是文件的末尾)

- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {

    switch(eventCode) {
        case NSStreamEventHasBytesAvailable:
        {
            if(!_data) {
                _data = [[NSMutableData data] retain];
            }
            uint8_t buf[1024];
            unsigned int len = 0;
            len = [(NSInputStream *)stream read:buf maxLength:1024];
            if(len) {
                [_data appendBytes:(const void *)buf length:len];
                // bytesRead is an instance variable of type NSNumber.
                [bytesRead setIntValue:[bytesRead intValue]+len];
            } else {
                NSLog(@"no buffer!");
            }
            break;
        }

答案 2 :(得分:0)

你也可以NSInputStream,它会减少你的内存使用量。 iOS设备上的14MB大量退出。