我理解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
表示它没有调用任何可以分配的东西。
答案 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
,我不会感到惊讶。同样,这应该是一个实现细节,不应该影响您使用的模式。