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
}
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
}
On Sun, Aug 27, 2017 at 6:59 PM, Peter Nicholls < swiftuser@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@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@swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
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.
What was the SR or radar number?
-Joe
···
On Aug 27, 2017, at 10:57 AM, Edward Connell via swift-users <swift-users@swift.org> wrote:
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
}
The only code generation difference I see, if I modify your didSet to make both calls is that the compiler treats function as a UTF-16 literal, whereas "counter" is recognized as an ASCII literal:
Michael, could there be a leak in the implementation of String(_builtinUTF16StringLiteral:utf16CodeUnitCount:)? The SIL at first glance looks balanced here.
-Joe
···
On Aug 27, 2017, at 10:57 AM, Edward Connell via swift-users <swift-users@swift.org> wrote:
import Foundation
class A {
var counter = 0 {
// didSet { onSet("counter") } // no leak
didSet { onSet() } // huge leak
}
On Mon, Aug 28, 2017 at 8:45 AM, Joe Groff <jgroff@apple.com> wrote:
> On Aug 27, 2017, at 10:57 AM, Edward Connell via swift-users < > swift-users@swift.org> wrote:
>
> 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"]!)
The only code generation difference I see, if I modify your didSet to make
both calls is that the compiler treats function as a UTF-16 literal,
whereas "counter" is recognized as an ASCII literal:
Michael, could there be a leak in the implementation of String(_
builtinUTF16StringLiteral:utf16CodeUnitCount:)? The SIL at first glance
looks balanced here.