[swift-users] Using #function causes big memory leak

Edward Connell ewconnell at gmail.com
Mon Aug 28 02:27:52 CDT 2017


Hi Peter, thanks for taking a look.

I would expect the compiler should generate a read only static string with
the name of the function whenever the #function directive is used. I would
expect that should not cause a leak.

If I modify the onSet function to replace a static string as the default
value instead of using #function, there is no leak, so this seems like a
bug to me.

Anyone have other ideas or opinions on this?

Thanks, Ed

--------------------------------------------------------
import Foundation

class A {
var counter = 0 {
// didSet { onSet("counter") }  // no leak
didSet { onSet() }  // huge leak
}

var properties = ["counter" : 0]
// func onSet(_ name: String = #function) { // leaks
// properties[name]! += 1
// }
func onSet(_ name: String = "counter") {  // no leak
properties[name]! += 1
}
}

var myclass = A()

for i in 0..<10000000 {
myclass.counter = i
}

print(myclass.properties["counter"]!)


On Sun, Aug 27, 2017 at 6:59 PM, Peter Nicholls <
swiftuser at peternicholls.co.uk> wrote:

> I looked in to the memory alloc and every time the “leak” iterates it’s
> creating an string item on the auto release stack with “counter” - a few
> million of them, compared to just 1 string on the non- leak. It is also
> quite a lot slower than the non leak version.
>
> I looked at the compiled assembly intermediate and at allocation the only
> difference is that the non-leak allocates via a register and is just a
> byte, but the leak uses a memory pointer is a word and is _unnammed_.
>
> My thought is that this isn’t a bug at all, it’s how the compiler deals
> with an unnamed #function and thus infers _name.
>
> As i trawled through the assembly seemed to me the non leak is making
> efficient use of the registers, through the named #function / _name, where
> as the leak version is using actual memory (hence why it is so much slower)
> with a view to destroying the autocomplete stack (of 9million odd auto
> release objects at 8bytes at a time) when completed. You can see how the
> memory stacks!
>
> Now. As to why and IF Swift is INTENDED to do this, or if indeed you’re
> doing something unintended too.... I cannot say.
>
> If any of the above is incorrect, please chime in.
>
> Peter Nicholls
> First time post.
>
> > On 27 Aug 2017, at 18:56, Edward Connell via swift-users <
> swift-users at swift.org> wrote:
> >
> > I reported this about a year ago, but it has never been fixed and it
> seems like it should be fixed for the Swift 4.0 release.
> >
> > Here is a simple repro case. If you watch the memory monitor as it runs,
> you see memory consumption climb to 2.7GB when using #function, and no
> memory increase when using a static string.
> >
> > import Foundation
> >
> > class A {
> >       var counter = 0 {
> > //            didSet { onSet("counter") }  // no leak
> >               didSet { onSet() }  // huge leak
> >       }
> >
> >       var properties = ["counter" : 0]
> >       func onSet(_ name: String = #function) {
> >               properties[name]! += 1
> >       }
> > }
> >
> > var myclass = A()
> >
> > for i in 0..<10000000 {
> >       myclass.counter = i
> > }
> >
> > print(myclass.properties["counter"]!)
> >
> > _______________________________________________
> > swift-users mailing list
> > swift-users at swift.org
> > https://lists.swift.org/mailman/listinfo/swift-users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170828/37bf549d/attachment.html>


More information about the swift-users mailing list