microsoft / Chakra-Samples

Repository for Chakra JavaScript engine related samples.
MIT License
216 stars 84 forks source link

Circular reference btw an object and a function object #44

Closed SrinivasGourarum closed 7 years ago

SrinivasGourarum commented 7 years ago

I have an implementation for say, a button control which gets created when I create an instance in JS as follows: var btn = new Button();

We have set a function object to handle the onclick functionality for the button as follows: btn.clickEvent = function(){ btn.setText = "new Text";//a property to set the text for the button }

This function object is held by the button control which when clicked executes the function object.

Upon referring to the btn instance inside the function object is creating a circular reference between the button and the function object. So the btn instance is never collected by the GC.

If the reference to the button is removed from the function object, the button is getting collected by the GC. Is there a way to ensure that one reference could be made a weak reference so that the button instance is always garbage collected?

liminzhu commented 7 years ago

You don't have to worry about circular reference @SrinivasGourarum. The btn object would be GC'able as long as it's not accessible from the stack or the heap.

SrinivasGourarum commented 7 years ago

Hi @liminzhu,

It has been observed that the btn object is never collected when referenced inside the function object. Let me try out a sample and see if it could reproduced.

liminzhu commented 7 years ago

Thanks @SrinivasGourarum. That would be extremely helpful to understand the issue.

SrinivasGourarum commented 7 years ago

Hi @liminzhu ,

The sample has been created. CircularRef.zip

In this sample we have a button instance which has the properties to set "text" and also a function object to handle "onClick" functionality. Also the finalize callback has been registered.

Launch the application and execute with the below script:

function doWork() { var btn = new Button(); btn.text="Click me"; btn.onClick= function() { btn.text="changed";//commenting this line will collect the button instance }; }; doWork();

Now click the button "Collect GC" so that we can force the GC to collect the button instance. We could see that the object is never collected. However, if we comment the reference to "btn" inside "onClick" the object is collected.

Please let me know if more information is needed.

Regards, Srinivas.

SrinivasGourarum commented 7 years ago

If it helps, this behavior has also been observed on JSCore and V8 engines.

liminzhu commented 7 years ago

@SrinivasGourarum sorry for the very late response :/. When I said earlier that you shouldn't worried about circular reference, I was thinking about between JS objects. But the btn object you have from C# correct? The C# and JS GC are separate entities and they don't really talk to each other, so a circular reference between the language boundaries would cause memory leak. It was a problem we've seen into before, and is a hard problem to solve. The best (but sadly not good) way to solve this is to break the reference when you want them to be GC'ed, e.g. deleting the event-handler function.

SrinivasGourarum commented 7 years ago

@liminzhu Thanks for the reply. Yes the btn object is implemented in C# and exposed to Javascript. Changing the text of a button upon clicking it seems like a general use case. It is rather strange to be not able to avoid memory leak in this case. Anyways, thanks for the clarification.

liminzhu commented 7 years ago

No problem @SrinivasGourarum. The button should probably always be live as long as the app is open? If that's the case, you don't want to GC the button and the handler anyways. Otherwise, you can manually break the linkage between the button and the handler whenever you want to re-claim that memory. It's a bit cumbersome, but the memory leak is avoidable.