4

我有一个我似乎无法弄清楚的问题。做了大量的搜索,尝试了大约 50 种不同的变体,到目前为止还没有骰子。这是我的困境。

我有3种方法。一个在我的 PageView 对象加载时调用,另一个在用户进行更改时调用,最后一个在用户离开页面时调用。

第一种方法:

- (void)captureInitialLinesTexture {
@autoreleasepool {
    self.initialLinesTextureCaptured = TRUE;
    GLubyte *buffer =(GLubyte *) malloc (1024 * 1024 * 4 * sizeof(GLubyte));
    glPixelStorei(GL_PACK_ALIGNMENT,1) ;
    glReadPixels(0, 0, 1024, 1024, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
    glBindTexture(GL_TEXTURE_2D, [pageTexture name]);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1024, 1024, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
    NSData __autoreleasing  *tempData = [NSData dataWithBytes:buffer length:1024*1024*4*sizeof(GLubyte)];
    if (textureData == nil) {
        textureData = [self.pageController.notebookDoc newTextureInPage:self.page];
    }

    [pageTextures addObject:tempData];
    if ([pageTextures count] > 5) {
        [pageTextures removeObjectAtIndex:0];
    }
    textureData.textureData = tempData;
    textureData.page = self.page;
    self.page.texture = textureData;
    self.page.lastLineId = [NSNumber numberWithInt:self.pageController.newLineId - 1];
    [self.pageController saveNotebookWithUndo:FALSE];
    free((GLubyte*)buffer);
  }
}

第二种方法:

-(void)capturePageTexture {
@autoreleasepool {
    GLubyte *buffer =(GLubyte *) malloc (1024 * 1024 * 4 * sizeof(GLubyte));
    glPixelStorei(GL_PACK_ALIGNMENT,1) ;
    glReadPixels(0, 0, 1024, 1024, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
    NSData __autoreleasing  *tempData = [NSData dataWithBytes:buffer length:1024*1024*4*sizeof(GLubyte)];
    [pageTextures addObject:tempData];
    if ([pageTextures count] > 5) {
        [pageTextures removeObjectAtIndex:0];
    }
    free((GLubyte*)buffer);
  }
}

最后一种方法:

-(void)attemptInstantPageTextureCapture {
  if ([pageTextures count] > 0) {
      self.page.texture.textureData = [pageTextures lastObject];
      self.page.lastLineId = [NSNumber numberWithInt:self.pageController.newLineId - 1];
      [self.pageController saveNotebookWithUndo:FALSE];
  }
  [pageTextures removeAllObjects];
  pageTextures = [NSMutableArray arrayWithCapacity:0];
}

我的问题是那些 NSData *tempData 变量。由于某种原因,其中一个在我的 PageView 消失后随机挂起(通过分配工具发现)。

如果我加载 PageView,captureInitialLinesTexture 会触发。然后,我可以添加大量笔触并在每次笔触后触发 capturePageTexture,在 NSMutableArray 名称 pageTextures 中最多保留 5 个 NSData 变量。当我离开 PageView 时, NSMutableArray 被清空。

现在这是它让人头疼的地方。NSData 的分配总是相同的大小,在这种情况下为 4mb。当页面加载时,我有 1 个 4mb 分配。如果我画笔画,我最多可以再画 5 个。然后,当我离开 PageView 时,最多有 5 个 4mb 分配(NSData)被释放,但我总是得到 1 个。如果我然后去仪器上的调用树,它会从第一种方法或第二种方法中随机说出它方法。为什么转储存储在数组中的 5 个 NSData 没有问题,但由于某种原因,1 个 NSData 在某处仍然存在。此外,这个神秘的 NSData 随机来自任一方法。

就像我说的,我已经搜索和搜索,找不到解决这个问题的方法。4MB 的内存显然是巨大的,因此任何此类泄漏都会随着时间的推移杀死应用程序。

一次尝试的分配: 一次尝试分配

调用 Tree 进行该尝试: 为该尝试调用树

分配给另一次尝试: 分配给另一次尝试

调用 Tree 进行其他尝试: 调用 Tree 进行其他尝试

每次都会触发相同的确切代码,并且每次 NSData 保持活动状态都是随机的。有人知道我做错了什么吗?如果您想知道,“page”和“textureData”变量是 NSManagedObjects。就我尝试过的事情而言:

在 NSData 对象上分配,然后调用 initWithBytes:length:

initWithBytesNoCopy:Length: - 没有调用 free((GLubyte*)buffer);

initWithBytesNoCopy:Length:freeWhenDone: - 没有调用 free((GLubyte*)buffer);

以上两种尝试的NSData类方法版本

不使用@autoreleasepool

不使用 __autoreleasing 进行 var 声明

使 NSMutableArray pageTextures 成为 PageView 的属性

在从 NavigationController 堆栈弹出之前将 PageView 设置为 nil

使用 __strong 遍历 pageTextures 可变数组并将所有 NSData 设置为 nil 或 null。

如上所述,这一切都发生在 PageView 类中,该类是 PageViewController 中的许多此类之一,该类被推送到导航控制器上然后从导航控制器中弹出。一旦 PageViewController(PageView 的唯一超级视图)从导航堆栈中弹出,一个随机的 NSData 分配仍然有效。

任何建议都将不胜感激!就上面提到的核心数据元素而言,代码完全按计划工作。唯一的问题是偷偷摸摸的实时 NSData 分配...... :(

4

3 回答 3

4

不久前解决了这个问题,但我想我会发布发生的事情,以防其他人有同样的问题。基本上,问题在于分配给核心数据实体的 NSData 对象,并且核心数据可以控制何时释放自己的内存。因此,虽然代码看起来不错,但核心数据仍然保留在 NSData 对象上,在它们超出范围并且运行循环完成之后(ARC 通常会启动)。

为了解决这个问题,我们只是将 NSData 保存到一个文件中,并更改了模型,以便核心数据实体只包含文件路径的字符串 (NSString) 而不是布尔数据 (NSData)。

问题解决了 :)

于 2012-05-31T14:50:33.837 回答
1

malloc当它在一个线程上分配的任何内容在另一个线程上被释放时,它不会释放。将您的代码包装在此:

dispatch_async(dispatch_get_main_queue(), ^{
    // malloc and whatever other code goes here...
});
于 2017-02-05T15:59:53.240 回答
0

__autoreleasing 关键字并不像您认为的那样做。它用于将包含未初始化指针的指针传递给初始化它们的方法。然后这些方法知道不保留它们初始化的值,因为它的唯一目的是返回以在调用方法中使用。在这种情况下你不需要它(默认的 strong 会很好,当它超出范围时会被释放)。删除该关键字时错误是否完全相同?

于 2012-05-15T01:05:16.467 回答