【问题标题】:Does CFSTR() allocate memory?CFSTR() 是否分配内存?
【发布时间】:2014-09-09 20:02:42
【问题描述】:

我理解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 在 Windows 或 Linux 上将 CFSTR 定义为 __builtin___CFStringMakeConstantStringexcept,它使用非内置版本。

所以答案似乎很可能是,“它不会在 MacOS X 或 iOS 上分配”。

我不知道如何验证它们实际上作为 CFStringRefs 存在于可执行文件中,但 otool -tV 说:

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

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

【问题讨论】:

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


    【解决方案1】:

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

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

    【讨论】:

    • 我明白了,回退实现使用 C 字符串值作为查找键,因此即使使用非文字字符串也会删除重复数据。但前提是你传入 ASCII!
    • 它也应该对非 ASCII 进行重复数据删除,但在这种情况下会收到警告。
    【解决方案2】:

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

    CFStringRef CFSTR (
        const char *cStr
    );
    

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

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

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

    【讨论】:

    • 谢谢,已修复。它在 Dash 中显示为功能,可能是查看器的限制。讨论部分清楚地表明它是一个宏。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-05
    • 2020-05-21
    • 1970-01-01
    • 2019-12-10
    • 2020-09-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多