Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider using finalizer and weak references to avoid leaks when proxies are abandoned #1017

Open
AArnott opened this issue Mar 12, 2024 · 2 comments

Comments

@AArnott
Copy link
Member

AArnott commented Mar 12, 2024

We might be able to allow finalization to recover leaked memory by:

  1. Generate proxies with a finalizer
  2. The finalizer should cause the connection to die (or an RPC marshaled object's resources to be recovered).
  3. If a proxy's backdoor interfaces are accessed such that another proxy or direct JsonRpc object access was obtained, shut off the self-destruct feature since we can no longer be confident that dropping the proxy indicates permanent loss of access to the JSON-RPC connection.
  4. To support proxies that raise events, JsonRpc should only retain a reference to it when there are actually handlers added to these events.

Note this is just a best-effort mitigation. The documentation should still emphasize the importance of disposing proxies.

@jacob-vincent-mink
Copy link

@AArnott +1 to this feature. Maybe you can tell me if the following situation below is related...

  1. Application A loads some Plugin.dll in a custom load context against common types (e.g. the DLL has SomeProducer, and implementation of IProducer that every DLL can use)
  2. Application B connects to Application A over RPC and calls a method over RPC that ends up getting an instance of SomeProducer (treated as IProducer everywhere necessary) as a proxy.
  3. Application A can no longer unload Plugin.dll due to references held within StreamJsonRpc (or maybe even lower layers?) by virtue of types from Plugin.dll having been serialized

Attached is a small toy example of the situation (zip of a 7z, sorry).
load_context_demo.zip

Related:
JamesNK/Newtonsoft.Json#2253
dotnet/runtime#13283

@AArnott
Copy link
Member Author

AArnott commented Apr 30, 2024

@jacob-vincent-mink, no, that's not the issue at hand here. This issue isn't about being able to unload assemblies. It's about being able to recover memory in the GC heap occupied by the proxy and maybe even drop the I/O connection itself when the proxy is dropped from all accessibility to the program.

An assembly is not expected to be unloadable after it has been used in RPC, because serializers tend to statically store information about types in that assembly as a perf optimization. There are APIs (at least in .NET 8) that allow us to store information in such a way that it would be discarded when an assembly is unloaded, but that isn't used consistently throughout the stack. I expect it would be a significant effort to achieve what you're describing. If you want that feature, please file a separate issue to track it. I don't expect we'll prioritize it anytime soon though, just to set expectations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants