核心数据 - 内存使用情况:我的应用程序崩溃

发布于 2024-11-07 16:47:42 字数 4563 浏览 0 评论 0原文

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

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

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

  • 使用核心数据执行提取
  • 对于每条记录,采用存储为行属性属性(字符串)的参数
  • 调用采用该参数并返回数据(大约数百 KB)的过程
  • 存储这些数据在同一行的另一个属性(可转换)中

很常见的任务不是吗?

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

  • 尽快释放拥有的对象
  • 创建自动释放池,并尽快将它们排空,对于不拥有的对象
  • 尽快保存上下文
  • 将对象转换为 应用所有这些技术后,

我得到了一个令人兴奋的结果:应用程序在与之前完全相同的点崩溃。

这是代码。

- (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 不值钱 信息,但我还是做了测试 我发现我可以发送 管理多个发布消息 强制应用程序之前的对象 为此崩溃。但重点是 我不应该发布 我不拥有的物体,是吗? ....
    • 设置请求的实体也有一些 与 的双向关系 其他实体,但仍然是这个 相关吗?

谢谢。

My question is about core data and memory usage. I have used core data before, but this time the amount of data is higher and this made me realise that there was much more to know. I have seen that there are several other similar posts and I got interesting information from them, but after applying it my apps still crashes. I have been dealing with this issue for a week now. Somebody please help.

Basically I have three subsequent similar loops of 64, 15, and 17 iterations respectively. They work fine on simulator. Tested on a couple of iPads they get memory warnings and they crash at the same iteration (number 34 of the first loop). Tested on iPad 2 it will crash at number 14 of the second loop. Instruments shows a memory usage of about 1.5 MB both live and overall. There are leaks for a few KB.

The loops perform the following (code below)

  • Execute a fetch with core data
  • For every record take a parameter stored as a row property attribute (String)
  • Call a procedure which takes that parameter and which returns data (about hundreds of KB)
  • Store these data in another property attribute (Transformable) of the same row

Pretty common task isn't it?

Now, since I got into memory issues, I tried to use the all the known (by me) tools at my disposal, which are:

  • release owned objects asap
  • create autorelease pools and drain them asap for not owned objects
  • save context asap
  • turn objects into faults asap

After applying all these techniques I got an exciting result: the app crashes at the exactly same point as before.

Here it is the code.

- (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;
}
  • Please note that

    • The mutable array was introduced as a (apparently useless) strategy to
      have objects released sooner
    • Pools have been added ad part of the same strategy
    • The statement about interpolation quality was the only one to improve
      the situation (say, to move the crash
      a little bit forward)
    • Retain count for managed objects within the cycle ranges from 6 to 10
      (?) I know that rc is not a valuable
      information but still, I made a test
      and I found out that I could send
      multiple release messages to managed
      objects before forcing the app to
      crash for this. But the point is that
      I am not supposed to release an
      object I don't own, am I? ....
    • The entity upon which the request is set has got also some
      bidirectional relationships with
      other entities, but still, is this
      relevant?

Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

帅气尐潴 2024-11-14 16:47:42

我认为你应该重新审视你的问题。
有很多处理核心数据的方法比您的方法简单得多。
为您的核心数据实体创建类文件可能会对您有所帮助。
另外,当你保存文件时,你应该认真评估每个对象的必要性以及是否可以做得更好。
对于您的情况,我会提供两个建议:


对于每个 PDF URL,

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

对于每个 PDF URL,

  • a. 绘制 PDF。
  • b.获取 UIImage 表示
  • c.转换为 PNG NSData
    (UIImagePNGRepresentation(image))
  • d. 将 NSData 保存到 CoreData 中。
  • e.加载NSData并转换为UIImage
    当需要时。

I think you should get a fresh look at your problem.
There are many ways to deal with Core Data that are much simpler than your approach.
Creating class files for your Core Data entities may help you.
Also, when you are saving your files, you should seriously evaluate each objects necessity and whether it can be done a better way.
In your case, I would offer two suggestions:


For each PDF URL,

  • a.Assign a unique identifier.
  • b.Save this unique identifier in your
    core data store.
  • c.Add url to a queue for a
    background process that creates
    your PDF (background process will
    allow the user to keep working while
    the PDFs are being generated. You
    could update your delegate on
    progress or create a temporary image
    that is replaced when the PDF is
    created.)
  • d.Save the image in your app
    directory (or photo library) using
    the unique identifier as a name.
  • e.When needed, load the image from
    disk into a UIImageView or
    whatever appropriate.

For each PDF URL,

  • a.Draw the PDF.
  • b.Get UIImage representation
  • c.Convert to PNG NSData
    (UIImagePNGRepresentation(image))
  • d.Save NSData in CoreData.
  • e.Load NSData and convert to UIImage
    when needed.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文