【问题标题】:Is it ok to use "classic" malloc()/free() in Objective-C/iPhone apps?在 Objective-C/iPhone 应用程序中使用“经典”malloc()/free() 可以吗?
【发布时间】:2010-11-12 03:32:03
【问题描述】:

我玩 iPhone 开发已经有一段时间了,虽然当你是一个“硬核”.NET 开发人员时感觉有点尴尬,但一旦你习惯了它并没有那么糟糕。

在我读过的关于 Objective-C 的每一本书中,只有关于内存管理的 retain/release(引用计数)。作为一个老派的 C/C++ 开发人员,使用 malloc()free() 的“正常”方式分配似乎很奇怪,仅在一些脚注中提及。

我知道 malloc()free() 在 Objective-C 中工作,但我很好奇这是否是常见的做法。毕竟,如果我想分配一个 100 个整数的数组,似乎这是最有效的方法:

int *array = malloc(sizeof(int) * 100);

memset(array,0,sizeof(int) * 100);

// use the array

free(array);

这确实是最好的方法,还是我应该避免使用普通的 C 内存管理?

【问题讨论】:

    标签: c objective-c memory-management


    【解决方案1】:

    有一个围绕原始内存的 Objective-C 包装器,我喜欢将它用于类似的任务:NSMutableData。它的好处是为您提供保留/释放所有权,而且它可以轻松扩展数组(无需您自己进行重新分配)。

    您的代码如下所示:

    NSMutableData* data = [NSMutableData dataWithLength:sizeof(int) * 100];
    int* array = [data mutableBytes];
    // memory is already zeroed
    
    // use the array
    
    // decide later that we need more space:
    [data setLength:sizeof(int) * 200];
    array = [data mutableBytes]; // re-fetch pointer in case memory needed to be copied
    
    // no need to free
    // (it's done when the autoreleased object is deallocated)
    

    【讨论】:

    • 我喜欢这个答案@Nikolai Ruhe。我使用“malloc”ed 数组作为属性。我有这个类的 3 个对象,我在 dealloc 中“释放”了数组。然而,在释放第一个对象后,我在释放第二个对象时收到“malloc: *** error for object 0x70a60: pointer being free was not assigned”错误!?看起来 malloc 是在“类级别”而不是“对象级别”完成的。切换到您的解决方案使这种情况消失了,但是对象的“行为”也发生了变化。还不知道为什么。
    • 好的,我试过了,但令我恐惧的是,最终发现我的“数组”充满了随机位。我猜在我完成数组之前,底层的“数据”是自动释放的。对数据进行“保留”可以解决该问题,但现在我必须保留对“数据”对象的引用,从而使该解决方案的吸引力降低。
    • @iPadDeveloper2011 你必须重新阅读内存管理编程指南developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/…
    • @iPadDeveloper2011:您需要重新学习内存管理。在这种特殊情况下,数据将被自动释放。只要自动释放池没有被耗尽,这段代码就可以了,但是一旦你达到可能存在自动释放池可能耗尽的范围,你就不能再使用数据了。如果您需要更长时间,那么您必须 retain 它,然后在完成后 release 它。
    • 我喜欢这个答案。当我需要使用整数数组并丢失引用计数并且能够轻松扩展它们时,我总是很困扰。感谢您提供非常好的解释和示例!
    【解决方案2】:

    这很好——Objective-C 是 C 的严格超集,所以如果你想编写普通的 C,没有什么能阻止你这样做。在许多情况下,使用mallocfree 可以避免Objective-C 运行时的开销。

    例如,如果您需要动态分配一个未知数量的整数数组,这通常更简单:

    int *array = malloc(N * sizeof(int));  // check for NULL return value!
    // use array[0]..array[N-1]
    ...
    free(array);
    

    对比:

    NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:N];
    // use NSMutableArray methods to do stuff with array; must use NSNumbers instead
    // of plain ints, which adds more overhead
    ...
    [array release];
    

    我正在为 iPhone 开发一个文字游戏,我们必须加载一个数兆字节的有效单词字典。单词列表被加载到分配有malloc() 的一个巨大的char 数组中,并进行了一些巧妙的优化以进一步减少内存大小。显然,对于这样的事情,使用NSArray 的开销在有限的 iPhone 上是完全不切实际的。我不确切知道开销是多少,但肯定是每个字符不止一个字节。

    【讨论】:

    • RE:'严格的超集'。虽然我个人(强烈)同意你的观点,但由于我们正在讨论 Apple/iPhone 的开发,所以这种说法在技术上并不正确。 Apple 如此定义它:Objective-C syntax is a superset of GNU C/C++ syntax。严格的超集有一个非常具体的含义,超集的无条件使用是两者中较小的一个(想想“表现得像”与“完全像”)。 syntax 的限定词进一步将其限制在几乎无用的地步,有效地将 Apple 的义务限制在 C99 规范的附件 A 中——标准中 552 页中的 16 页。
    • 我在 Objective C 中使用 malloc/free 时遇到了很多问题。请参阅我对 Nikolai 答案的评论。除此之外,我在分配(复制)指向 malloced 数组的指针以在对象之间共享 malloced 数组时遇到了问题。
    • 虽然您确实可以使用 malloc() 和 free(),但您可以通过使用适当长度的 NSMutableData 来避免大部分运行时开销。
    【解决方案3】:

    当然,您可以使用这些函数,因为 Objective-C 只是 C 的超集。然而,做这种事情相当少见,因为 Objective-C 包含对象和使这更容易的方法。

    毕竟,你可以把上面的代码写成:

    NSMutableArray *array = [[NSMutableArray alloc] init];
    
    //Use the array, adding objects when need be
    
    [array release];
    

    虽然您必须创建NSNumber 对象来存储ints(因为NSArray 不允许添加非对象类型),但通常更常见的是使用对象,因为它是更容易移动数据,并且数组类更普遍地与其他 Cocoa 类集成,内存管理通常比标准 C 内存管理更直接。

    此外,如果您开始在数组中添加或删除对象,那么 Cocoa 数组对象会让这件事变得更容易。

    【讨论】:

    • 如果您需要一个简单的整数数组,这似乎有点过头了。特别是创建 NSNumber 对象的需求对我来说似乎效率很低。如果我想分配一个包含 100,000 个布尔值的数组怎么办?
    • 与使用简单的整数数组相比,可能会有一点开销。但它们肯定比使用 C 内存管理更常用。如果您要分配一个包含 100,000 个布尔值的数组,那么可能有比您当前实现它的方式更好的方法(除非这是一个假设场景)。
    • 如果您正在处理非常简单的对象,这尤其过大。例如,如果您要为 iPhone 构建 MineSweeper,将正方形作为结构体并 malloc 结构体数组比将正方形创建为对象并将它们放入中要快数量级一个 NSArray。此外,您将使用更少的内存。
    • 当然,这取决于问题的上下文,但使用标准 C 内存管理相当少见。此外,正如我所说,如果您正在操作数组项,它们会变得更加有用。
    • 只想指出,100,000 个布尔值(BOOL?)的数组已经是一种内存效率低下的解决方案,因为每个 BOOL 是 1 个字节,但您实际上只需要 1 个位。因此,使用 100,000/8 个字符的数组和按位运算符要好 8 倍。
    【解决方案4】:

    如果您正在处理标准 C 类型,它并不比在 C 中更常见或“OK”。这就是它在 C 中的处理方式,它是 Objective-C 的一部分。

    围绕这些东西编写某种对象包装器以使其与 Cocoa 的其余部分(KVO、内存管理等)协调一致也很常见。因此,您可以创建一个 IntArray 类,在幕后执行 mallocing,以便您可以根据需要保留和释放它。请注意,这并不是绝对必要的——如果这种结构是您程序的主要部分,它会很方便。

    【讨论】:

      【解决方案5】:

      完全可以使用 malloc 和 free 来做你自己的内存管理。其实NSObject的allocWithZone:使用malloc来获取内存。

      【讨论】:

      • 它在技术上是 calloc,但是是的。 =)
      • 实际上,它在技术上是NSAllocateObject()。接下来发生的事情更复杂。在启用 GC 的 ObjC2 下,NSAllocateObject() 调用 objc_allocate_object()。在 ObjC2 w/o GC 或 ObjC NSAllocateObject() 调用 class_createInstanceFromZone(),后者又调用 malloc_zone_calloc(),顾名思义,这在逻辑上等价于 calloc()。具有1countcalloc() 定义为无法从malloc 获得的相同size 获得的分配中获得space is initialized to all bits zero (C99 7.20.3.1.2)。
      猜你喜欢
      • 2011-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-19
      • 1970-01-01
      • 1970-01-01
      • 2017-06-14
      相关资源
      最近更新 更多