Why does this leak?


(Rick Aurbach) #1

I have a situation where I have a leak that I do not understand. I would be very grateful if someone could explain it to me and offer an idea of how I can make the pattern work without leaking:

Consider two code snippets, the first of which leaks, while the second does not.

Case 1: This example leaks 2 32-byte objects..

in FontSelectorDialog.swift:
  override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  switch segue.identifier! {
  < ... >
  
  case "ChooseTextColor" :
    let target = segue.destination as! ColorChooser
    target.textChooserType = .text // <===
    < ... >
    }
    
  case "ChooseBackgroundColor" :
    let target = segue.destination as! ColorChooser
    target.textChooserType = .bkgnd // <===
    < ... >
    }
    
  default : break
  }

in ColorChooser.swift:

internal enum ColorCat { // <===
  case: .text // <===
  case: .bkgnd // <===
} // <===

internal class ColorChooser : UITableViewController {
  internal var textChooserType : ColorCat = .text // <===
  < ... >
}

Case 2: This example does not leak...

in FontSelectorDialog.swift:
  override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  switch segue.identifier! {
  < ...>
    
  case "ChooseTextColor" :
    let target = segue.destination as! ColorChooser
    target.textChooserType = true // <===
    < ... >
    }
    
  case "ChooseBackgroundColor" :
    let target = segue.destination as! ColorChooser
    target.textChooserType = false // <===
    < ... >
    }
    
  default : break
  }

in ColorChooser.swift:

internal class ColorChooser : UITableViewController {
  internal var textChooserType : Bool = true // <===
  < ... >
}

Can someone explain why? And how can I implement this using an enum. I want to use an enum here because:
(a) it is easier to read and understand and seems more “swiftly”
(b) Someday, I may want to add additional options, which would be easy with an enum but difficult using the current (Bool) implementation.

Cheers,

Rick Aurbach


(Alex Blewitt) #2

How are you determining that this is leaking? There was an issue in Xcode where the 'leaks' detector was unable to introspect the memory layout of a Swift object containing an enum stored property and incorrectly flagging other such reachable objects as leaks. If that's the case, do you still see the same behaviour flagged in the latest Xcode?

Alex

···

On 26 Mar 2017, at 18:43, Rick Aurbach via swift-users <swift-users@swift.org> wrote:

I have a situation where I have a leak that I do not understand. I would be very grateful if someone could explain it to me and offer an idea of how I can make the pattern work without leaking:


(Rick Aurbach) #3

Okay, I downloaded the latest Xcode from the developer site. (The download page said it was 8.3beta5, but the version info called it 8.3 (8E161).)

So I put the use of the enum back into my code and profiled it again. (Please refer to my original post for the Case 1 code that I’m testing here.)

According to the Leaks Instrument, there is still a leak (just one 32-byte block, rather than two) coming from the call to prepare.

Unless I’m missing something REALLY basic here, using the enum as in my original post should not leak. (Right??) So either there is a compiler issue (still present in the compiler version of Xcode 8E161) or there is an issue in the Leaks Instrument (still present in the latest Xcode).

This is frustrating, because I don’t want to release a product with known leaks, but I don’t really know at this point whether I have one or whether I’m just seeing an artifact. Suggestions??

Cheers,

Rick Aurbach

···

On Mar 27, 2017, at 3:01 AM, Alex Blewitt <alblue@apple.com> wrote:

On 26 Mar 2017, at 18:43, Rick Aurbach via swift-users <swift-users@swift.org> wrote:

I have a situation where I have a leak that I do not understand. I would be very grateful if someone could explain it to me and offer an idea of how I can make the pattern work without leaking:

How are you determining that this is leaking? There was an issue in Xcode where the 'leaks' detector was unable to introspect the memory layout of a Swift object containing an enum stored property and incorrectly flagging other such reachable objects as leaks. If that's the case, do you still see the same behaviour flagged in the latest Xcode?

Alex


(David Sweeris) #4

Could you call the supposedly leaky code a few million times and look at memory usage to see if there's actually a leak?

- Dave Sweeris

···

On Mar 27, 2017, at 13:31, Rick Aurbach via swift-users <swift-users@swift.org> wrote:

Okay, I downloaded the latest Xcode from the developer site. (The download page said it was 8.3beta5, but the version info called it 8.3 (8E161).)

So I put the use of the enum back into my code and profiled it again. (Please refer to my original post for the Case 1 code that I’m testing here.)

According to the Leaks Instrument, there is still a leak (just one 32-byte block, rather than two) coming from the call to prepare.

Unless I’m missing something REALLY basic here, using the enum as in my original post should not leak. (Right??) So either there is a compiler issue (still present in the compiler version of Xcode 8E161) or there is an issue in the Leaks Instrument (still present in the latest Xcode).

This is frustrating, because I don’t want to release a product with known leaks, but I don’t really know at this point whether I have one or whether I’m just seeing an artifact. Suggestions??

Cheers,

Rick Aurbach

On Mar 27, 2017, at 3:01 AM, Alex Blewitt <alblue@apple.com> wrote:

On 26 Mar 2017, at 18:43, Rick Aurbach via swift-users <swift-users@swift.org> wrote:

I have a situation where I have a leak that I do not understand. I would be very grateful if someone could explain it to me and offer an idea of how I can make the pattern work without leaking:

How are you determining that this is leaking? There was an issue in Xcode where the 'leaks' detector was unable to introspect the memory layout of a Swift object containing an enum stored property and incorrectly flagging other such reachable objects as leaks. If that's the case, do you still see the same behaviour flagged in the latest Xcode?

Alex

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Rick Aurbach) #5

That wouldn’t work directly. The “leak” occurs when processing a segue called in response to a user button push. (I suppose I could attempt to wire up a UI Test, but would rather not go down that route.)

What I can try is to see if I can create a simple, artificial example. If it also reports a leak, then I could try looping it. I’ll look into it in the morning.

Cheers,

Rick Aurbach

···

On Mar 27, 2017, at 6:11 PM, David Sweeris <davesweeris@mac.com> wrote:

Could you call the supposedly leaky code a few million times and look at memory usage to see if there's actually a leak?

- Dave Sweeris

On Mar 27, 2017, at 13:31, Rick Aurbach via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Okay, I downloaded the latest Xcode from the developer site. (The download page said it was 8.3beta5, but the version info called it 8.3 (8E161).)

So I put the use of the enum back into my code and profiled it again. (Please refer to my original post for the Case 1 code that I’m testing here.)

According to the Leaks Instrument, there is still a leak (just one 32-byte block, rather than two) coming from the call to prepare.

Unless I’m missing something REALLY basic here, using the enum as in my original post should not leak. (Right??) So either there is a compiler issue (still present in the compiler version of Xcode 8E161) or there is an issue in the Leaks Instrument (still present in the latest Xcode).

This is frustrating, because I don’t want to release a product with known leaks, but I don’t really know at this point whether I have one or whether I’m just seeing an artifact. Suggestions??

Cheers,

Rick Aurbach

On Mar 27, 2017, at 3:01 AM, Alex Blewitt <alblue@apple.com <mailto:alblue@apple.com>> wrote:

On 26 Mar 2017, at 18:43, Rick Aurbach via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

I have a situation where I have a leak that I do not understand. I would be very grateful if someone could explain it to me and offer an idea of how I can make the pattern work without leaking:

How are you determining that this is leaking? There was an issue in Xcode where the 'leaks' detector was unable to introspect the memory layout of a Swift object containing an enum stored property and incorrectly flagging other such reachable objects as leaks. If that's the case, do you still see the same behaviour flagged in the latest Xcode?

Alex

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users


(Alex Blewitt) #6

You could try doing something like:

static let choser:ColorChoser = ColorChoser()
choser.textChoserType = .text

Run that in Xcode and see if it shows a leak.

Alex

···

On 28 Mar 2017, at 05:41, Rick Aurbach <rlaurb@icloud.com> wrote:

That wouldn’t work directly. The “leak” occurs when processing a segue called in response to a user button push. (I suppose I could attempt to wire up a UI Test, but would rather not go down that route.)

What I can try is to see if I can create a simple, artificial example. If it also reports a leak, then I could try looping it. I’ll look into it in the morning.


(Rick Aurbach) #7

This is getting interesting.

I added your suggested test code (set to execute once):
class FontSelectorDialog : UITableViewController {

  static let chooser : ColorChooser = ColorChooser()
  
  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    FontSelectorDialog.chooser.textChooserType = .text
  }

  < . . . >
}

BY THE WAY — I didn’t think to mention this previously, but the “leaking” code is in a framework and I put the suggested test code in the same framework.

Using Xcode 8.3:

(1) Running Simulator for iPhone 7+ (10.3), profiling the code, neither your suggested test code NOR the original code shows a leak in the Leaks Instrument.

(2) Running on an iPad Air 2 (10.2), profiling the code, your suggested test code does NOT show a leak, but the original code DOES. (The stack trace for the leak point is at the bottom of this email.)

I haven’t taken the next step of attempting to build a simple example to see if I can duplicate the problem in a simple project. I’d like to pursue this because it is increasingly looking like a “not my” bug, and I’d like to prevent others from spending as much time on this issue as I have already.

Cheers,

Rick Aurbach

That wouldn’t work directly. The “leak” occurs when processing a segue called in response to a user button push. (I suppose I could attempt to wire up a UI Test, but would rather not go down that route.)

What I can try is to see if I can create a simple, artificial example. If it also reports a leak, then I could try looping it. I’ll look into it in the morning.

You could try doing something like:

static let choser:ColorChoser = ColorChoser()
choser.textChoserType = .text

Run that in Xcode and see if it shows a leak.

Alex

   0 libsystem_malloc.dylib malloc_zone_malloc
   1 libsystem_malloc.dylib malloc
   2 libswiftCore.dylib swift_slowAlloc
   3 libswiftCore.dylib _swift_allocObject_
   4 libswiftCore.dylib _swift_allocObject_
   5 RLAFontSelector specialized RLAFontSelectorDialog.prepare(for : UIStoryboardSegue, sender : Any?) -> () /Users/rlaurb/Projects/RLAFontSelector/Sources/RLAFontSelectorDialog.swift:0
   6 RLAFontSelector RLAFontSelectorDialog.prepare(for : UIStoryboardSegue, sender : Any?) -> () /Users/rlaurb/Projects/RLAFontSelector/Sources/RLAFontSelectorDialog.swift:0
   7 RLAFontSelector @objc RLAFontSelectorDialog.prepare(for : UIStoryboardSegue, sender : Any?) -> () /Users/rlaurb/Projects/RLAFontSelector/Sources/RLAFontSelectorDialog.swift:0
   8 UIKit -[UIStoryboardSegueTemplate _performWithDestinationViewController:sender:]
   9 UIKit -[UIStoryboardSegueTemplate _perform:]
  10 UIKit -[UIStoryboardSegueTemplate perform:]
  11 UIKit -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:]
  12 UIKit -[UITableView _userSelectRowAtPendingSelectionIndexPath:]
  13 UIKit _runAfterCACommitDeferredBlocks
  14 UIKit _cleanUpAfterCAFlushAndRunDeferredBlocks
  15 UIKit _afterCACommitHandler
  16 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
  17 CoreFoundation __CFRunLoopDoObservers
  18 CoreFoundation __CFRunLoopRun
  19 CoreFoundation CFRunLoopRunSpecific
  20 GraphicsServices GSEventRunModal
  21 UIKit -[UIApplication _run]
  22 UIKit UIApplicationMain
  23 PoetsCorner main /Users/rlaurb/Projects/PoetsCorner/PoetsCorner/SettingsController.swift:13
  24 libdyld.dylib start

···

On Mar 28, 2017, at 4:14 AM, Alex Blewitt <alblue@apple.com> wrote:

On 28 Mar 2017, at 05:41, Rick Aurbach <rlaurb@icloud.com> wrote: