【问题标题】:Core Data - memory usage: my app crashes核心数据 - 内存使用:我的应用程序崩溃
【发布时间】:2011-08-24 21:49:02
【问题描述】:

我的问题是关于核心数据和内存使用情况。我以前使用过核心数据,但这次数据量更高,这让我意识到还有很多东西要知道。我看到还有其他几个类似的帖子,我从他们那里得到了有趣的信息,但是在应用之后我的应用程序仍然崩溃。我已经处理这个问题一个星期了。请有人帮忙。

基本上我有三个后续类似的循环,分别是 64、15 和 17 次迭代。他们在模拟器上工作正常。在几台 iPad 上进行了测试,它们收到内存警告,并且在同一迭代中崩溃(第一个循环的第 34 号)。在 iPad 2 上测试它会在第二个循环的 14 号崩溃。 Instruments 显示实时和整体的内存使用量约为 1.5 MB。有几 KB 的泄漏。

循环执行以下操作(代码如下)

  • 使用核心数据执行提取
  • 为每条记录获取一个存储为行属性属性(字符串)的参数
  • 调用一个接受该参数并返回数据(大约数百 KB)的过程
  • 将这些数据存储在同一行的另一个属性属性(Transformable)中

很常见的任务不是吗?

现在,由于我遇到了内存问题,我尝试使用我可以使用的所有已知(由我自己)工具,它们是:

  • 尽快释放拥有的对象
  • 为不拥有的对象创建自动释放池并尽快排空它们
  • 尽快保存上下文
  • 尽快将对象变成故障

应用所有这些技术后,我得到了一个令人兴奋的结果:应用程序在与之前完全相同的时间点崩溃。

这是代码。

- (void) myMainProcedure {
    [self performLoop1];
    [self performLoop2];  // Similar to loop1
    [self performLoop3];  // Similar to loop1
}
- (void) performLoop1 {
    NSError * error = nil;
    NSAutoreleasePool * myOuterPool;
    NSAutoreleasePool * myInnerPool;

    NSManagedObjectContext * applicationContext = [[[UIApplication sharedApplication] delegate] managedObjectContext];
    [applicationContext setUndoManager:nil];


    NSEntityDescription * myEntityDescription = [NSEntityDescription entityForName:@"EntityName"
                                               inManagedObjectContext:applicationContext];
    NSFetchRequest * myFetchRequest = [[NSFetchRequest alloc] init];
    [myFetchRequest setEntity:myEntityDescription];

    NSString * column = @"columnName";
    NSPredicate * aWhereClause = [NSPredicate predicateWithFormat:
                                  @"(%K = %@)", column, [NSNumber numberWithInt:0]];
    [myFetchRequest setPredicate: aWhereClause];

    myOuterPool = [[NSAutoreleasePool alloc] init];
    NSArray * myRowsArray = [applicationContext executeFetchRequest:myFetchRequest                                                                     
                                                              error:&error];
    NSMutableArray * myRowsMutableArray = [[NSMutableArray alloc] initWithCapacity:0];
    [myRowsMutableArray addObjectsFromArray: myRowsArray];
    [myOuterPool drain];
    [myFetchRequest release];

    EntityName * myEntityRow;
    int totalNumberOfRows = [myRowsMutableArray count];

    myOuterPool = [[NSAutoreleasePool alloc] init];
    for (int i = 0; i < totalNumberOfRows; i++) {

            myInnerPool = [[NSAutoreleasePool alloc] init];
            myEntityRow = [myRowsMutableArray objectAtIndex:0];
            NSString * storedSmallAttribute = myEntityRow.smallAttribute;
            UIImageView * largeData = [self myMethodUsingParameter: smallAttribute];
            myEntityRow.largeAttribute = largeData;
            [myRowsMutableArray removeObjectAtIndex:0];

            [applicationContext save:&error];
            [applicationContext refreshObject:myEntityRow mergeChanges:NO];
            [myInnerPool drain];
            [largeData release];
    }
    [myOuterPool drain];
    [myRowsMutableArray release];
}

- (UIImageView *)  myMethodUsingParameter : (NSString *) link { 
    UIImageView * toBeReturned = nil;
    NSURL *pdfURL = [NSURL fileURLWithPath:link];
    CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);
    CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);
    CGRect pageRect = CGPDFPageGetBoxRect(page, kCGPDFMediaBox);
    UIGraphicsBeginImageContext(pageRect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();   
    CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
    CGContextFillRect(context,pageRect);
    CGContextSaveGState(context);
    CGContextTranslateCTM(context, 0.0, pageRect.size.height);
    CGContextScaleCTM(context, 1, - 1);
    CGContextSetInterpolationQuality(context, kCGInterpolationHigh); 
    CGContextSetRenderingIntent(context, kCGRenderingIntentDefault);
    CGContextDrawPDFPage(context, page);
    CGContextRestoreGState(context);
    UIImage *imageToBeReturned = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    CFRelease(pdf);  
    toBeReturned = [[UIImageView alloc] initWithImage:imageToBeReturned];
    UIGraphicsEndImageContext();
    return toBeReturned;
}
  • 请注意

    • 可变数组是作为一种(显然无用的)策略引入的 尽快释放对象
    • 已添加池作为同一策略的一部分
    • 关于插值质量的声明是唯一需要改进的声明 情况(比如说,移动崩溃 向前一点)
    • 在从 6 到 10 的周期范围内为托管对象保留计数 (?)我知道 rc 不是有价值的 信息,但我还是做了一个测试 我发现我可以发送 多个发布消息到托管 强制应用程序执行之前的对象 为此崩溃。但重点是 我不应该发布 我不拥有的对象,是吗? ....
    • 设置请求的实体也有一些 双向关系 其他实体,但仍然,这是 相关吗?

谢谢。

【问题讨论】:

  • 为什么要返回并存储 UIImageView 而不是图像?

标签: iphone ipad core-data memory-management loops


【解决方案1】:

我认为你应该重新审视你的问题。 有很多方法可以处理 Core Data,它们比你的方法简单得多。 为您的 Core Data 实体创建类文件可能会对您有所帮助。 此外,当您保存文件时,您应该认真评估每个对象的必要性以及是否可以以更好的方式完成。 在你的情况下,我会提出两个建议:


对于每个 PDF URL,

  • a.分配一个唯一标识符。
  • b. 将此唯一标识符保存在您的 核心数据存储。
  • c.将 url 添加到队列中以获取 创建的后台进程
    您的 PDF(后台进程将
    允许用户在工作的同时继续工作 正在生成 PDF。你
    可以更新您的代表
    进展或创建临时图像 当 PDF 为
    已创建。)
  • d.将图像保存在您的应用程序中 目录(或照片库)使用 作为名称的唯一标识符。
  • e. 需要时,从 磁盘放入 UIImageView 或
    任何合适的。

对于每个 PDF URL,

  • a.绘制 PDF。
  • b.获取 UIImage 表示
  • c.转换为PNG NSData (UIImagePNGRepresentation(图像))
  • d.将 NSData 保存在 CoreData 中。
  • e.Load NSData 并转换为 UIImage 需要时。

【讨论】:

  • 感谢您的回答。我认为您是对的,这我需要重新审视一下,但我似乎找不到方法。
  • 感谢您的回答。我认为你是对的,我需要重新审视这一点,但我似乎找不到方法。顺便说一句,第一个建议听起来是个好主意,即使我没有多线程方面的经验。第二个建议或多或少是我想要做的,即使没有转换为 NSData。现在让我们假设选择第二种方法。我们需要从核心数据中获取一些记录,然后在属性中设置一个大的 NSData 来更新它们。如何安排这个循环来防止内存问题?你能发布任何代码或类似代码吗?
  • 我认为真正对您有所帮助的是阅读一些关于 Core Data 的优秀基础材料。您需要了解 Core Data 如何分配和存储信息、如何检索信息等。这里有一个很好的教程可以帮助您入门:
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-28
  • 1970-01-01
  • 2011-10-06
相关资源
最近更新 更多