导致“虚拟内存耗尽”错误的原因是什么?

时间:2015-02-10 21:13:20

标签: objective-c xcode allocation

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

在模拟器中,一切都运行完美无瑕,在我的iPhone(4S)上大约100张图像上它崩溃并出现错误:

  

malloc: * mach_vm_map(size =“some random number”)失败(错误代码= 3)* 错误:无法分配区域

     

libBacktraceRecording.dylib:allocate_free_list_pages() - 虚拟内存耗尽!

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

-(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];
}

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

3 个答案:

答案 0 :(得分:2)

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

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

        // loop body goes here...

    }
}

答案 1 :(得分:1)

在使用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];
        } }

希望这可以帮助其他人解决同样的问题。好运和快乐的编码!

答案 2 :(得分:0)

使用了你的所有建议和可能的解决方案,但是,对不起,没有用。

在这种情况下,当应用需要下载大量照片时,你真的应该使用SDWebImageDownloader Class Reference

我知道改变整个方法并实现以前的方法(下载照片)是没用的,所以HERE是关于如何使用SDWebImageDownloader类的教程和示例。祝你好运。