CFSTR()是否分配内存?

时间:2014-09-09 20:02:42

标签: c macos memory memory-leaks core-foundation

我理解CFSTR() documentation表示它分配了内存。它可以在失败时返回NULL,并且结果可用,直到程序终止,无论是否调用CFRelease()或删除引用。它包装静态字符串,但肯定必须分配一个CFString类结构来执行此操作。因此,它不适合在长期运行的程序中使用。

然而,经过一番回击,我尝试了以下测试程序。我没有看到top内存占用增加。 valgrind报告的泄漏不随循环大小而变化。是否发生了重复数据删除?

#include <CoreFoundation/CFString.h>
#include <stdio.h>

int main(void) {
  int count = 0;
  int chars = 0;
  for (int i = 0; i < 100000000; i++) {
    CFStringRef str = CFSTR("Goodbye.");
    if (str) {
      count++;
      chars += CFStringGetLength(str);
      // Drop reference!
    }
  }
  printf("%d strings, %d chars\n", count, chars);
  CFStringRef str = CFSTR("Hello, World.");
  CFShowStr(str);
}

另一位提问者reported CFSTR()在Windows上泄露了。其他人说它与Objective C的@"String"字面语法相似。 CFString参考提到在gcc 3.3上需要-fconstant-cfstrings。那么宏是否使用魔术编译器扩展来在构建时创建它们?

在我的MacOS X 10.8.5计算机上,CoreFoundation / CFString.h将CFSTR定义为__builtin___CFStringMakeConstantString ,除了在Windows或Linux上,它使用非内置版本。

所以这似乎是答案,&#34; 它不会在MacOS X或iOS上分配&#34;。

我不知道如何验证他们实际上是否在CFStringRefs的可执行文件中,但otool -tV说:

leaq    0x1c8(%rip), %rax ## Objc cfstring ref: @"Goodbye."

指令指针相对寻址是一些确认,leaq表示它没有调用任何可以分配的东西。

2 个答案:

答案 0 :(得分:5)

正如您所发现的,在Apple平台上,CFSTR使用内置的编译器在编译时生成字符串。它作为一个完全构造的可用对象嵌入在可执行文件中;程序在CFSTR运行时不会执行任何分配。编译器在单个转换单元中合并重复的字符串对象。我不确定链接器是否在目标文件中合并重复项。

在其他平台上,Apple无法控制编译器,因此它无法使用内置的编译器将构造对象嵌入到可执行文件中。相反,在运行时,它调用私有库函数__CFStringMakeConstantString。您可以在CFString.c中找到此功能的源代码。它保留一个哈希表,将参数(作为C字符串)映射到CFString。这是“重复数据删除”。它通常不会从表中删除条目。因此传递给CFSTR的每个唯一C字符串将分配一些持续存在直到程序存在的内存。任何使用相同字符串参数的CFSTR调用都可以访问内存,因此将其称为“泄漏”是值得怀疑的。

答案 1 :(得分:0)

CFSTR是一个类似函数的宏,它使用const char *并返回CFStringRef

CFStringRef CFSTR (
    const char *cStr
);

正如您所提到的,文档提供了一些有趣的警告。我个人会将它们视为实现细节,并管理您从中获取的CFStringRef由创建规则保留,相应地平衡保留/释放调用。

(至于它可能分配或不分配的原因,我认为编译器可以选择通过创建永久CFSTR()来优化CFStringRef调用,就像拥有NSString *str = @"MyString!";一样会这样做,但我没有数据支持这个。)

编辑:就重复数据删除而言,如果它搜索一堆现有的已初始化的CFStringRef,我不会感到惊讶。同样,这应该是一个实现细节,不应该影响您使用的模式。