microsoft / ClearScript

A library for adding scripting to .NET applications. Supports V8 (Windows, Linux, macOS) and JScript/VBScript (Windows).
https://microsoft.github.io/ClearScript/
MIT License
1.77k stars 148 forks source link

Dispose, destruct, reference counting of C# objects #525

Closed simontom closed 1 year ago

simontom commented 1 year ago

Hey guys, is there any way how to recognize the object passed to JS got out of scope and can be disposed automatically?

Something like this:

C# [ScriptMember] ObjectToBeDisposed GetObject() => new ObjectToBeDisposed();

JS (for example for, or recursion, or a scope of a function)

for (let i = 0; i < 42; i++) {
    const destructorObject = GetObject();
}
simontom commented 1 year ago

Well, I forgot, sorry.... What I have alredy tried is using a plain destructor ~ObjectToBeDisposed() of the C# object. But, of course, it ain't a reliable way

ClearScriptLib commented 1 year ago

Hi @simontom,

is there any way how to recognize the object passed to JS got out of scope and can be disposed automatically?

We aren't clear on what you're trying to do. Please help us understand your scenario.

Perhaps this'll help: When you pass a .NET object to script code, the script engine gets a proxy – a script object that holds a strong reference to the original object. Assuming that no other strong references are outstanding, the original object doesn't become eligible for garbage collection until the script engine releases the proxy. In JavaScript, that happens only when the proxy is reclaimed by the JavaScript garbage collector.

Thanks!

simontom commented 1 year ago

Let's say I have something like this

class ObjectToBeDisposed: IDisposable
{
    void Dispose() => Console.WriteLine("Disposed");
}

class Service
{
    [ScriptMember("getObject")]
    ObjectToBeDisposed GetObject() => new ObjectToBeDisposed();
}

Service's instance is passed to the CSEngine, so I could call service.getobject()

Now, I have something like this

for (let i = 0; i < 42; i++) {
    const obj = service.getObject();
}

I understand:

My question is if there is any way how we can recognize the loss of reference / getting out of scope, so, we would be able to call Dispose automatically? Any interface that would make the proxy to call to the .Net object?

ClearScriptLib commented 1 year ago

Hi @simontom,

It sounds like you're looking for a hook that would allow you to call a managed object's Dispose method when the corresponding proxy is about to be collected by the script engine.

If that's correct, then, unfortunately, there's no such hook. Would it be possible for you to track your references manually? Your script code would probably have to adhere to some sort of acquire/release contract for these objects.

Good luck!

simontom commented 1 year ago

Yes, that's correct, something like a hook we could react to when the proxy is out of scope.

Do u have anything concrete up on your mind? I see no way that the (even JS) object itself could be informed of not being used anymore (being out of scope, having no strong reference) as u wrote there is no such hook.

Well, it's OKay for us to add something like ˙JS ObjectToBeDisposed.close()˙. Was looking for a better, "no-code for user", solution.

If you've told me everything already, let's close this issue.

ClearScriptLib commented 1 year ago

Do u have anything concrete up on your mind?

Managing shared disposable objects is a common problem in .NET, and reference counting is a typical solution. Essentially, GetObject would either create a new object or bump the count on an existing one, and then a method called Release would decrement the count and call Dispose if it's zero.

If you've told me everything already, let's close this issue.

Thanks. Please reopen it if you have any additional thoughts or questions.