可以使用“吗?”;经典;Objective-C/iPhone应用程序中的malloc()/free()?

可以使用“吗?”;经典;Objective-C/iPhone应用程序中的malloc()/free()?,c,objective-c,memory-management,C,Objective C,Memory Management,我玩iPhone开发已经有一段时间了,虽然当你是一个“硬核”的.NET开发人员时会觉得有点尴尬,但一旦你习惯了,就不会那么糟糕了 在我读过的每一本关于Objective-C的书中,都只谈到了内存管理的保留/释放(引用计数)。作为一名老的skool C/C++开发人员,使用malloc()和free()分配“正常”方式似乎很奇怪,只是在一些脚注中提到了这一点 我知道malloc()和free()在Objective-C中工作,但我很好奇这是否是常见的做法。毕竟,如果我想分配一个100个整数的数组,

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

在我读过的每一本关于Objective-C的书中,都只谈到了内存管理的
保留
/
释放
(引用计数)。作为一名老的skool 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内存管理?

使用malloc和free来进行自己的内存管理是完全可以的。实际上,NSObject的
allocWithZone:
使用malloc获取内存。

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

毕竟,您可以将上述代码编写为:

NSMutableArray *array = [[NSMutableArray alloc] init];

//Use the array, adding objects when need be

[array release];
虽然您必须创建
NSNumber
对象来存储
int
s(因为
NSArray
不允许添加非对象类型),但通常使用对象更为常见,因为它更易于移动数据,而且数组类更常与其他Cocoa类集成,内存管理通常比标准的C内存管理更简单

另外,如果您开始从数组中添加或删除对象,那么Cocoa数组对象会使这一操作变得更容易。

这很好——Objective-C是C的严格超集,因此如果您想编写纯C,没有什么可以阻止您这样做。在许多情况下,使用
malloc
free
可以避免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开发一个文字游戏,我们必须加载一个有效单词的多兆字节字典。单词列表被加载到一个巨大的
char
数组中,该数组分配了
malloc()
,并进行了一些巧妙的优化,以进一步减小内存大小。显然,对于这样的情况,在有限的iPhone上使用
NSArray
的开销是完全不现实的。我不知道具体的开销是什么,但每个字符肯定超过一个字节。

如果你处理的是标准C类型,它的常见程度或“OK”程度不亚于C。这就是C的工作方式,C是Objective-C的一部分


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

在原始内存周围有一个Objective-C包装器,我喜欢在类似任务中大量使用它:
NSMutableData
。它的好处是为您提供保留/发布所有权,并且可以轻松地扩展阵列(无需您自己进行realloc)

您的代码如下所示:

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)

如果您需要一个简单的整数数组,这似乎有些过分。尤其是创建NSNumber对象的需要对我来说效率太低了。如果我想分配一个100000个布尔值的数组呢?也许,与使用简单的整数数组相比,可能会有一些开销。但它们肯定比使用C内存管理更常用。如果你正在分配一个100000个布尔数组,那么可能有一个比你目前实现它更好的方法(除非这是一个假设的场景)。如果你处理的是非常简单的对象,这尤其是过火了。例如,如果要为iPhone构建“扫雷舰”,将正方形作为结构,将malloc作为结构数组要比将正方形创建为对象并将其放入NSArray快几个数量级。另外,您将使用更少的内存。当然,这取决于问题的上下文,但使用标准C内存管理是相当少见的。另外,正如我所说,如果你在操作数组项,它们会变得更有用。我想指出的是,一个100000布尔(BOOLs?)的数组已经是一个内存效率低下的解决方案,因为每个BOOL是1字节,但实际上只需要1位。因此,使用100000/8个字符的数组和按位运算符大约是8倍。从技术上讲,这是calloc,但是是的。=)实际上,它在技术上是
NSAllocateObject()
。接下来发生的事情更加复杂。在启用GC的ObjC2下,
NSAllocateObject()
调用
objc\u allocate\u object()
。在不带GC的ObjC2或ObjC<2下,
NSAllocateObject()
调用
class\u createInstanceFromZone()
,后者依次调用
malloc\u zone\u calloc()
,顾名思义,后者在逻辑上等同于
calloc()
。根据定义,计数为
1
calloc()
可以从
malloc
获得的具有
空间的
相同
大小的分配中被初始化为所有位0
(C99 7.20.3.1.2)。RE:“严格超集”。虽然我个人(强烈)同意你的观点,但由于我们正在讨论苹果/iPhone的开发,这一说法在技术上并不正确。苹果这样定义它: