0

I don't know why this simple piece of code can cause memory leak sometimes (not always).

This piece of code is wrapped in an NSOperation and runs in an NSOperationQueue queue. The operation will trim sourceNSAString to fit in some size and return it to some other thread as a result.

//sourceNSAString is a NSMutableAttributedString that will be set to nil elsewhere in another GCD queue.
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef) sourceNSAString); 

if (frameSetter) {

    CFRange fitRange = {static_cast<CFIndex>(range.location), 0};

    CFRange totalRange = {static_cast<CFIndex>(range.location), static_cast<CFIndex>(range.length)};

    CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(frameSetter, totalRange, NULL, size, &fitRange);

    CFRelease(frameSetter);

      ...... trim sourceNSAString to fit in fitRange
 }

Is it because: 1, I should not return sourceNSAString to another thread ? or 2, CTFramesetterCreateWithAttributedString can't be used in background thread ?

Any ideas? Thanks!

Jay Zhao
  • 946
  • 10
  • 24
  • See http://stackoverflow.com/questions/8491841/memory-usage-grows-with-ctfontcreatewithname-and-ctframesetterref/17248890#17248890 for root cause. – MoDJ Jun 22 '13 at 08:49

3 Answers3

0

OK, it seems that it's a simulator bug (at least for now). I profiled my App on a device and the memory leak just disappeared. Simulator seems to have a lot of memory leaks when using core text in multi-thread environment. For example, create a CTFrameSetter and release it in the same GCD serial queue later (which is allowed according to the Doc) can cause memory leak randomly. Anyway all those memory leaks just go away when profiled in a real device.

Jay Zhao
  • 946
  • 10
  • 24
0

This leak is not just a simulator bug, it shows up on the actual device. See my answer to this related question for in depth debugging Memory usage grows with CTFontCreateWithName and CTFramesetterRef

Community
  • 1
  • 1
MoDJ
  • 4,309
  • 2
  • 30
  • 65
-2

i think you should release frameSetter after if statement, because if the if statement isn't executed the frameSetter doesn't get released.

    CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef) sourceNSAString); 

if (frameSetter) {

    CFRange fitRange = {static_cast<CFIndex>(range.location), 0};

    CFRange totalRange = {static_cast<CFIndex>(range.location), static_cast<CFIndex>(range.length)};

    CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(frameSetter, totalRange, NULL, size, &fitRange);

 }

CFRelease(frameSetter);

this should work

Lukas
  • 2,515
  • 4
  • 28
  • 37
  • But if "if (frameSetter)" is false then there's no need to release a NULL ref right? And if it's true, it will get released absolutely. – Jay Zhao Jul 16 '12 at 15:29
  • More importantly, if it's NULL, then CFRelease() will crash, so you'd have to check against NULL again. The original code is correct. – Rob Napier Jul 22 '12 at 17:48