How to destroy a LiveAPI object instantiated in JS ?

Jan 25, 2012 at 3:55pm

How to destroy a LiveAPI object instantiated in JS ?

Everything in the title :p

Putting objects in a table, I tried to :
- put null in the array slots
- put a new object invoked with “id 0″ (which of course, on the JS Live API side gives an error)

any tips for me ?

#61449
Feb 14, 2012 at 5:22am

If you allow a variable to go out of scope, it will automatically be destroyed by Javascript’s garbage collector.

So I assume you still have references to it somewhere. Is there a callback associated with it? I’m not sure how to remove a callback…

Javascript does have a delete operator – try that and see if it works…

#221679
Feb 14, 2012 at 9:00am

I found a workaround for this particular case (another request/callback architecture in my script)
but yes the garbage collector works… in “pure” javascript.
I guess there was something else and the callback weren’t destroyed correctly.

#221680
Feb 15, 2012 at 8:30pm

I spent a little time tracking this down, just for my own satisfaction.

In fact, if you create a LiveAPI instance and a callback, it’s unclear how exactly those two objects could ever get garbage collected!

For example, suppose you have the following code:

{
  var live;
  function callback() {
    post(live.get('name')[0], 'n');  // Called whenever the track name changes, forever.
  };

  live = new LiveAPI(callback, 'this_device canonical_parent');
  live.property = 'name';
}

The function “callback” is called immediately with the current track name and continues to be called every time the track name changes, even though both “live” and “callback” have gone out of scope. Clearly there’s some global list of “LiveAPI instances with callbacks that need to be updated” which keeps “live” from being garbage collected, and which in its turn keeps “callback” from being garbage collected – but there’s no way to get “live” off the callback update list, or at least none in the documentation – Why don’t a tags work?.

Now, it turns out that “live”, the LiveAPI object, has an undocumented field called “cb_private” which contains the pointer to the callback. Adding the code delete live.cb_private; to your callback stops further callbacks:

{
  var live;
  function callback() {
    post(live.get('name')[0], 'n');    // Only called once, because the next line
    delete live.cb_private;             // prevents any further callbacks.
  };

  live = new LiveAPI(callback, 'this_device canonical_parent');
  live.property = 'name';
}

But does that actually free the LiveAPI instance? It’s unclear.

It’d have to be removed from my hypothetical callback update list. Perhaps whatever code maintains that checks each time to see if cb_private is null, and if so removes the LiveAPI from the update list – perhaps it only does this check when it adds the LiveAPI to the callback update list – perhaps this the “callback list” is accomplished with some other mechanism I haven’t even thought of!

It’s hard to see how to test this directly, but you could test indirectly by creating a lot of these LiveAPIs in a tight loop and trying to free them in the callback. If you weren’t actually freeing them, then eventually you’d run out of memory… might take a long time though if these are quite small.

If there’s interest, I’ll run the test… :-)

#221681
Feb 15, 2012 at 8:39pm

nice shot !
as soon as I’ll need that (means quite soon), I’ll test it.
I hope someone from C74 will help us here :)

#221682
Feb 16, 2012 at 3:42am

(btw, sorry for the weird link label – for whatever reason, I was unable to get a link to appear at the time, but now I refresh the page I see it is as link… strange!

#221683
Mar 20, 2014 at 7:57pm

Hi,

Im wondering how cb_private works if you want to delete observers and then create new ones?

For instance, if I run some JS and set up a bunch of observers, when I run the js next time (to delete the old observers and set up some new ones), how can I delete the observers? Do they get deleted on each run anyway?

The usage shown in the example seems to delete observers after the first callback. How can they be deleted “on demand”, or on run of next execution?

My concern is that each time the script is run, new observers are being set up, are the old ones deleted/garbage collected?

#284423
Mar 21, 2014 at 2:53am

You need to set the property back to empty (null) – this will remove the observer from the internal lists.

Nothing is done automatically in js for the observers – you have to manage them all explicitly.

#284446
Mar 21, 2014 at 3:13am

maybe can we use “freepeer” method for it . it works for Dict’s , Polybuffers so maybe for other constructors or instances also . im just guessing

#284448
Mar 21, 2014 at 3:56am

?? don’t understand – setting the monitored property back to null clears the observation of that property, what more needs to be done?

#284452
Mar 21, 2014 at 4:02am

just asking Lee . i had in mind just the instance of an API not observers . a bit off here , sorry

#284453
Mar 21, 2014 at 4:04am

(so happy this thread has initiated progressively a deep discussion!)

I can understand that C74′s dudes don’t reveal too much, but we’d need that, actually ;)

#284454
Mar 21, 2014 at 4:13am

dw… no problem mate, just wondered if there was something I was missing… :)

#284456
Mar 21, 2014 at 5:38am

Thanks Lee,

Im wondering how would to set the properties to Null?

In the following code, would I just run through the same IDs/Paths again, to setting “obsids[i].property” to null instead of value?

for (i = 0; i < leng; i++) {
obsids[i] = new LiveAPI(callback, "id "+arguments[i]);
obsids[i].is_observing = false;
obsids[i].property = "value";
obsids[i].is_observing = true;

}
}
function callback(args)
{
outlet(0, args[0] + " " + args[1] + " " + this.id + " " + this.is_observing);
}
}

#284468
Mar 21, 2014 at 5:54am

yes, just do:

obsids[i].property = “”;

for each one (I checked my code and I actually set it to the empty string rather than null – I’m guessing I did this for a reason as normally I would just null something like that out)

#284470
Mar 21, 2014 at 10:45am

Works perfectly. Thanks Lee :)

#284519
Mar 29, 2014 at 7:41am

Ive been testing this thoroughly over the last few days. Im coming to the conclusion that setting them to “” empty or null doesnt stop these observers still working away in the background (although they do stop outputting values). Im trying to put a patch together to demonstrate this, but its hard because you only notice it when you are observing lots of IDs at once and the only thing to notice is that observers are slowing down.

If I create say 200 observers for an Operator, then use hot-swap in live to switch the parameters. It takes around 3 seconds to hot-swap. If I then delete the observers and re-create them, it takes 5 seconds to hot swap. Each time I delete/recreate the observers there is a few seconds added to hot-swap, which demonstrates that although the observers may be deleted and not outputting any values, they are still working away in the background.

The reason why I suspect the observers are still working in the background and not being garbage collected is because the behaviour when they are deleted (ie resulting in slower and slower observing), is the same as when new observers are created over and over again (without deleting the old ones).

Ive tried with both “delete live.cb_private;” and with setting null or empty strings and while they both do stop the observers outputting values, clearly they are still working in the background.

#285205
Mar 29, 2014 at 9:04am

Ok, so I have finally managed to make a test patch to show this in more detail.

The way this works is it measures the amount of seconds between updating the first and last parameter of an operator device. You have to put this device to the right of an operator. Then click bang, then hot-swap 2-3 times. Then keep clicking bang and hotswapping 2/3 times, each time checking the speed of hot-swap in the print window.

Here are my results (which seem conclusive):

1st Button press (creation of observers)

Hotswap 1 – 1.14s
Hotswap 2 – 1.14s
Hotswap 3 – 1.13s

2nd Button press (delete and recreate observers)

Hotswap 1 – 2.10s
Hotswap 2 – 2.09s
Hotswap 3 – 2.09s

3rd Button press (delete and recreate observers)

Hotswap 1 – 3.05s
Hotswap 2 – 3.06s
Hotswap 3 – 3.06s

This goes on until I run out of memory I guess. JS is definitely not removing those observers. However, I have a feeling that the live.observer object behaves exactly the same way (its just easier to produce a demo in JS).

Any thoughts?

Ive sent the patch into C74. Hopefully theyll come back to me with some explanation :/

#285207
Mar 29, 2014 at 12:28pm

Hi. This again exists in the MxDCore code owned by Ableton. The observer is being disabled (as in the fact it is no longer a registered callback), but there is a data structure that is not being cleared down properly. Hence, over time this grows and causes the issue. These are two separate items as far as the code is concerned. Let’s try and get the Abes to look at the first issue first, then will move onto this one :) As well as proposing a solution to this I will also propose a new call is added so that we can remove all current observers for the current device. This should simplify things a lot. Currently, this only happens, and the only way of getting this to happen, is to remove the device.

#285217
Mar 29, 2014 at 12:31pm

By first issue I mean the one that we are discussing in the other thread… And ultimately, fixing that will also make this kind of go away, but this should still be addressed for completeness tho…

#285218
Mar 31, 2014 at 2:15am

Newtfish, are you on L8 and not L9?

#285302
Mar 31, 2014 at 3:44am

L9, you think this might be to do with L9 only?

#285309
Mar 31, 2014 at 4:08am

No, it’s definitely both. I have a replacement MxDCore which fixes the main issue for now but only for L9. send me your email address to admin@sigabort.co.uk and I’ll send it over tonight if you want to give it a go.

#285315

You must be logged in to reply to this topic.