是什么导致 "Virtual Memory exhausted" 错误?

What causes a "Virtual Memory exhausted" error?

好吧..事情是这样的..我正在构建一个应用程序,当用户点击下载按钮时,它会下载一堆图像(准确地说是 296)。

在模拟器中一切正常,在我的 iPhone (4S) 上大约第 100 张图像上它崩溃并出现错误:

malloc: * mach_vm_map(size= "some random number") failed (error code= 3)* error: can't allocate region

libBacktraceRecording.dylib: allocate_free_list_pages() -- virtual memory exhausted!

这是我为下载这些图片而编写的代码:

-(void)getData
{
    NSError *error;
    int i;
    NSArray *brojLinije = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"linije" ofType:@"plist"]];
    NSArray *urlSlike = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"urlSlike" ofType:@"plist"]];
    NSArray *pocetno = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"pocetno" ofType:@"plist"]];
    NSArray *sortiranje = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"sort" ofType:@"plist"]];
    NSArray*paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *desktopDir = [paths firstObject];
    UIImage *image1 = [[UIImage alloc] init];

    for (i = 0; i<296; i++) {

        NSString *brojLinije1 = [NSString stringWithFormat:@"%@",[brojLinije objectAtIndex:i]];
        NSString *pocetno1 = [NSString stringWithFormat: @"%@", [pocetno objectAtIndex:i]];
        NSString *tableSort = [NSString stringWithFormat: @"%@", [sortiranje objectAtIndex:i]];
        image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat: @"http://www.busevi.com/images/stories/Red-Voznje/Gradski-Prevoz-BG/linija.%@.png", [urlSlike objectAtIndex:i ] ]]]];
        NSData *data1 = [NSData dataWithData:UIImageJPEGRepresentation(image1, 0.1)];

        NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
        NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
        NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];

        NSString *pngFilePath = [NSString stringWithFormat:@"%@%@.jpg",desktopDir,[urlSlike objectAtIndex:i]];
        [data1 writeToFile:pngFilePath atomically:YES];

        [newManagedObject setValue:brojLinije1 forKey:@"brojLinije"];
        [newManagedObject setValue:data1 forKey:@"imageData"];
        [newManagedObject setValue:pocetno1 forKey:@"pocetnoStajaliste"];
        [newManagedObject setValue:tableSort forKey:@"sort"];
        NSLog(@"%d / 296", i);
    }

    [self.managedObjectContext save:&error];
}

我唯一知道的是图像分配频率(分配太多而没有时间自动释放)造成了问题,并且我已经尝试了目前为止我知道的所有方法,而且我已经看了很多"Instruments" 应用教程,只有一个帮助(找到填充虚拟内存的来源),但我仍然无法解决我的问题。

您可以在循环内部使用局部 autorelease pool 来立即释放在循环主体中创建的任何对象。

for (i = 0; i<296; i++) {
    @autoreleasepool {

        // loop body goes here...

    }
}

采纳了你和我的所有建议和可能的解决方案,但是,很抱歉,none 成功了。

在这种情况下,当应用需要下载大量照片时,您确实应该使用 SDWebImageDownloader Class Reference

我知道更改整个方法并意识到以前的方法(下载照片)是无用的,所以 HERE 是关于如何使用 SDWebImageDownloader Class 的教程和示例。祝你好运。

在使用 SDWebImage 框架时,我遇到了很多错误和应用程序无法解决的崩溃。如果要下载的图像数量低于 SDWebImage,那就太棒了,比方说 50。因为,当一张一张地下载 TableViewCell + 快速滚动(快速闪烁)中显示的图像时,应用程序会收到几次内存警告TableView 仍在滚动时的次数(SDWebImage 仅当 TableView 缓慢滚动或根本不滚动时才会清除内存)所以它使应用程序崩溃。

因此,我对下载 300 多张图片时应用程序崩溃的唯一安慰是简单的 Apple 方法,称为 dispatch_async。更多信息 here.

这就是我解决问题的方法(我只需要将所有内容从我原来的 -(void)getdata 方法移动到 dispatch_async 块。完成! 所以现在看起来像这样:

-(void)getData {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"Downloading Started");
        slike = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"slike" ofType: @"plist"]];
        brojevi = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"linije" ofType:@"plist"]];
        pocetnaStajalista = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"pocetno" ofType:@"plist"]];
        sort = [[NSArray alloc]initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:@"sort" ofType:@"plist"]];

        NSEntityDescription *entity = [NSEntityDescription entityForName:@"Linija" inManagedObjectContext:self.managedObjectContext];
        NSString *brojLinije;
        NSString *pocetnoStajaliste;
        NSString *sortiranje;
        NSData *data;
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString  *documentsDirectory = [paths objectAtIndex:0];

        NSString  *filePath = [NSString stringWithFormat:@"%@/%@", documentsDirectory,@"filename.png"];

        for (int i = 0; i<314; i++) {
            NSManagedObject *novaLinija = [[NSManagedObject alloc]initWithEntity:entity insertIntoManagedObjectContext:self.managedObjectContext];

            brojLinije = [NSString stringWithFormat:@"%@",brojevi[i]];
            pocetnoStajaliste = [NSString stringWithFormat:@"%@",pocetnaStajalista[i]];
            data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat: @"http://www.busevi.com/images/stories/Red-Voznje/Gradski-Prevoz-BG/linija.%@.png",slike[i]]]];
            [data writeToFile:filePath atomically:YES];
            sortiranje = [NSString stringWithFormat: @"%@", sort[i]];

            [novaLinija setValue:data forKey:@"slikaLinije" ];
            [novaLinija setValue:brojLinije forKey:@"brojLinije"];
            [novaLinija setValue:pocetnoStajaliste forKey:@"pocetnoStajaliste"];
            [novaLinija setValue:sortiranje forKey: @"sort"];
            NSLog(@"%d / 314", i+1);
            NSError *error;
            [self.managedObjectContext save:&error];
        } }

希望这对遇到同样问题的其他人有所帮助。祝你好运,编码愉快!