-
Notifications
You must be signed in to change notification settings - Fork 18
[WIP] Stop heartbeats when tearing down the Environment #30
base: master
Are you sure you want to change the base?
Conversation
This is almost done. Heartbeats are stopped when Heart is destroyed, and most of them get destroyed. The ones that aren’t destroyed, are the ones created using the HeartbeatBridge. Something’s not right with memory management there, but I’m not sure what. I tried disabling this call in HeartbeatBridge.swift JSContext.currentContext().virtualMachine.addManagedReference(self, withOwner: self) but it didn’t help. Any ideas? |
One more thing – |
HeartbeatBridge never gets called even if you remove the addManagedReference call, and you don’t assign the new Heartbeat instance to a variable in global scope?
|
Here saniul@adbeae6:
Now, when you run the Color Puddles scene - |
Yikes. Uh. My next step would probably be to use Instruments to look at who's hanging onto it. About to run out for the day, but I can check that out tomorrow if you'd like! |
👍 I’ll take a look later today |
So I tracked it down to the JSContext not being destroyed. Looks like just setting an empty function as a That, in turn, prevents HeartbeatBridge from being destroyed. |
Alright, so the cycle looks something like this: LayerBridge ---> Layer ---> touchXXXHandler closure ---[captures]---> touchXXXHandler function ---> JSContext ---> LayerBridge ---> ∞ The JS function implicitly retains the JSContext because it needs it to be able to execute. If we prevent the touchXXXHandler closure from capturing the JS function then it gets deallocated. |
…in closures that are (transitively) owned by the JSContext. Temporary shim using Environment.associated objects
In saniul@4be7518 I avoid capturing the JS function objects in closures. Instead I associate the JS function objects with the Environment, so they get destroyed whenever the Environment gets destroyed. This is a temporary measure, I just wanted to demonstrate that this does indeed solve the retain cycle problem. We could expose the current |
Nice. Gotcha. Thanks very much for the research! I'm really disappointed that Swift makes it so easy to invisibly make these kinds of mistakes. At least it's slightly harder than in Obj-C. But still. Anyway: When |
Sounds good, will do. Sent from my iPhone
|
Argh, looks like that isn’t possible after all. |
Yuck. Set the value for all those properties to null?
|
Tried already – didn’t help |
Okay, watched WWDC 2013 #615 again. They actually warn about exactly this kind of issue. The suggestion: Instead of having our closure capture the JS function, we can have it capture a |
Sorry, I realize that was kinda vague. Something like:
|
So annoying – looks like there’s another retain cycle hiding somewhere. Interestingly, it goes away if I don’t pass |
Conflicts: Examples/Color Puddles/main.js
Yuck! I hadn't realized it, but isn't that because the
|
Conflicts: Prototope/Environment.swift
Nope, the |
Yikes. Okay. Will jump in when I get a chance; may not be for a few days.
|
Hm, @saniul, I just tried your branch (well, with One new issue I do observe, though, is that I have to assign the heartbeat to a global to make it stay around:
|
Ok, I’m back, had an unplanned trip dropped on me this past week. Looks like 8.3 introduces a bunch of JavaScriptCore stuff (including what looks like ECMAScript 6’s class support?). I’m downloading 6.3 right now, will have a look at this PR and the new JSC things (there might be something useful for our bridge) later today. |
Very odd, I’m still seeing the same behavior I reported earlier. Were you testing the Color Puddles demo or some other one?
Here’s how you can see things aren’t cleaned up properly: I’m logging the #of Layers and LayerBridges that are kept around in memory (simple counter, increments on init, decrements on deinit). If you just keep resaving Color Puddles/main.js without interacting with the scene – the count is balanced. If you even touch the screen once – the count grows by 2 (meaning that two Layers and LayerBridges weren’t destroyed). |
Thanks for that! I'm observing that the heartbeat stops executing (i.e. the logging stops), but that the layers stick around, as you mention. If I comment out the lines in the heartbeat closure which refers to |
Argh, okay, I still haven't gotten to the bottom of this, and I need to turn my attention to other things for now, but I discovered something interesting: if you comment out the |
Resolves #29 (comment)
Introduces the
Heart
object owned by theEnvironment
, which holds references to all theHeartbeats
in that environment.