简体   繁体   中英

Does CFSTR() allocate memory?

I understood the CFSTR() documentation to indicate that it allocates memory. It can return NULL on failure, and the result is available until the program terminates regardless of whether one calls CFRelease() or drops the reference. It's wrapping the static string, but surely it has to allocate a CFString class struct to do so. And as such it's not appropriate to use in long-running programs.

However, after some pushback on this, I tried the following test program. I don't see the memory footprint in top increase. The leaks reported by valgrind don't vary with the loop size. Is there de-duplication happening?

#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);
}

Another asker reported that CFSTR() does leak on Windows. Others say it's like Objective C's @"String" literal syntax. The CFString reference mentions needing -fconstant-cfstrings on gcc 3.3. So does the macro use a magic compiler extension to create these at build time?

On my MacOS X 10.8.5 machine, CoreFoundation/CFString.h defines CFSTR as __builtin___CFStringMakeConstantString except on Windows or Linux, where it uses a non-builtin version.

So this seems likely the answer is, " It doesn't allocate on MacOS X or iOS ".

I don't know how to verify they're actually in the executable as CFStringRefs, but otool -tV says:

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

Instruction pointer relative addressing is some confirmation, and leaq means it's not calling anything which could allocate.

As you discovered, on Apple platforms, CFSTR uses a compiler built-in to generate the string at compile time. It is embedded in the executable as a fully-constructed, usable object; the program doesn't perform any allocation at runtime for CFSTR . The compiler merges duplicate string objects within a single translation unit. I'm not sure if the linker merges duplicates across object files.

On other platforms, Apple doesn't control the compiler, so it can't use a compiler built-in to embed a constructed object in the executable. Instead, at runtime, it calls the private library function __CFStringMakeConstantString . You can find the source code of this function in CFString.c . It keeps a hash table that maps the argument (as a C string) to a CFString . This is the “de-duplication”. It generally doesn't remove entries from the table. So each unique C string passed to CFSTR will allocate some memory that persists until the program exists. The memory is accessible by any call to CFSTR with the same string argument, so calling it a “leak” is questionable.

CFSTR is a function-like macro that takes a const char * and returns a CFStringRef .

CFStringRef CFSTR (
    const char *cStr
);

As you mention, the documentation provides a few interesting caveats. I would personally treat them as implementation details and manage the CFStringRef you get from it as being retained by the create rule, balancing retain/release calls accordingly.

(As far as the reason why it may or may not allocate, I think the compiler has the option to optimize out a CFSTR() call by creating an immortal CFStringRef just like having NSString *str = @"MyString!"; would do, but I have no data to support this.)

EDIT : As far as de-duplication goes, I wouldn't be surprised if it searches a heap of existing initialized CFStringRef s. Again, this should be an implementation detail and shouldn't affect the patterns you use.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM