How to safely free memory for object created with JS ?
Hi there,
my JS code create Max Objects on the patcher (=not encapsulated in JS)
I keep a trace of all objects created in JS arrays in order to be able to have a reference to them and to pass data, track etc.
If I want to make a safe clean, to free completely the memory related to that, I'm removing my objects from the patcher, but what SHOULD I do with my arrays ?
Actually, I'm basically doing that:
myArray.length = 0;
When I'm using JAVA, I have to explicitely call freePeer() method for each instantiated object.
BUT should I do that in JS if my code already removed the objects in the patcher ...?
( I guess no, but I'd prefer to be sure)
I think js have a GC you don't worried about that..
If I'm not wrong .. max object pointer was managed by max application it self ...when created max object in javascript object you just got a reference to that object ... may be you can use yourObjectArray[n].valid to check state of your ref.
Yes in a browser JS will auto GC depending on scope of the var, I assume max adhere's to that. I guess it's analogous to having a var reference an element to the DOM, if the var no longer exists, the element still will, unless you call an element.removeChild(). You can also do a delete on elements in an array but again it will only delete the pointer to the object.
hi there,
many thanks for your answers.
I got it
Can you share your solution? I have tried all kinds of things and the observer is still there.
observer? Are you using max for live? care to share your js?
some very old code are still available on my protodeck page:
https://julienbayle.studio/protodeck-custom-midi-controller-for-ableton-live/
never achieved to remove observer callbacks, btw.
Sure, for example let's say you want to observe the selected track but only when you have your controller set to a certain mode. The observer js:
var selTrackObserver = new LiveAPI(observeSelTrack);
selTrackObserver.path = 'live_set view';
selTrackObserver.property = 'selected_track';
function observeSelTrack(args) {
if (args[0] === 'selected_track') {
outlet(0, args[2]);
}
}
but this applies to any observer. I'd like to observe the number of devices in the selected track and the on/off states for each device, but only when I'm in a certain mode on my controllers. I know how to observe them but I don't know how to do the equivalent of sending 'id 0' to an actual live.observer object in max. The callback never goes away no matter what.
I would either re instantiate the observer with the above code when you are in observing mode or put an if statement in the 1st line of the callback checking if you are in the right mode.
Ah, thanks, in my desperation to find a solution in my search I rushed past the title of this post and thought it had to do with stopping a js observer. Don't think I'll have a solution for this, which means I'd have to keep a static number of observer objects outside of js if I want to turn them off :/ Not ideal.
hmm it's kind of related actually, I will just fire up m4l as I'm interested in this
I would either re instantiate the observer with the above code when you are in observing mode or put an if statement in the 1st line of the callback checking if you are in the right mode.
Yes the conditions are there and I've tried different ways to change the callback but the problem is is that once the function gets called it will not go away. I tried using the function as an exrpression to change itself into something else when going out of the mode, or 'delete' and even gc() doesn't work.
I appreciate the help.
Also to note, once the callback gets instantiated again, ie going out of mode and then back in, it's like instantiating a new function on top of the previous one, meaning the callbacks build up each time.
FYI: I use this function so that I can send info straight to the max window without having to send out an outlet to print:function log() {
for(var i = 0, len = arguments.length; i < len; i++) {
var message = arguments[i];
if(message && message.toString) {
var s = message.toString();
if(s.indexOf("[object ") >= 0) {
s = JSON.stringify(message);
}
post(s);
}
else if (message === null) {
post("<null>");
}
else {
post(message);
}
}
post("\n");
}
so instead of the lineoutlet(0, args[2]);
it sayslog(args[2]);
yes you're absolutely right LiveApi references aren't GC'd.
selTrackObserver.id = 0; seems to stop the original callback firing, could you do that?
alternatively check a flag on the callback to see if it is in the right mode.
omg you know what, I tried changing selTrackObserver tp New LiveAPI('id 0') but I don't think I actually did yours and now I feel like an idiot lol. I'll take your word for it but I can't check until much later tonight.
Thank you so much!
Ok in some defense I was way past my bedtime when I was experimenting with it but DUH
no worries, the docs says api = new LiveAPI([callback], [path]/[id]);
so I guess internally it's doing type assertions to decide how to handle each arg and id is a number.
Seems once id is set to 0 the object is destroyed, you can't resurrect it by assigning a new valid id again.
Hmm, sounds like it may make the whole thing moot then unless there's some js workarounds....?
Can't find out until later but thanks for the info
you should be good to go with id=0
I've only had a little time to test but so far there's no difference.
I'll try having a conditional in using an expression instead of outer callback but I already tried a conditional in the callback and it crashed live.
So far it's been like thisif (mode=== 1) {
selTrack = new LiveAPI(observeSelTrack,'live_set view');
// selTrack.path = 'live_set view';
selTrack.property = 'selected_track';
} else {
// selTrack = new LiveAPI('live_set');
selTrack = {};
// selTrack.path = '';
// selTrack.property = '';
selTrack.id = 0;
}
but nada...I'm wondering if scope may have to do with it
yes selTrack must be in scope it's probably not. Make sure it's defined outside of any functions to make it global
It's working!!!
I had selTrack already declared globally but not as a new LiveAPI.
For reference, the trick is to put the path back when the mode is on:
if (mode) {
selTrack.path = 'live_set view';
} else {
selTrack.id = 0;
}
and globally it's set as:var selTrack = new LiveAPI(observeSelTrack,'live_set view');
selTrack.property = 'selected_track';
Now I'll have to see how this works out when it comes to being able to switch the observers of the devices on/off as well but this is a great first step. Have my babies omg
cool glad you got it sorted