Ownership analysis for deterministic GC/deallocation #97292
Unanswered
fabianoliver
asked this question in
Ideas
Replies: 1 comment 1 reply
-
@dotnet/gc is there any recent interest on this? |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Apologies if this idea/question is rather high-level and not very specific. I've been curious though if the following would be possible and sensible at all though.
If you're about to think "well someone just read about Rust's memory ownership model and spend all of 5 minutes thinking whether .NET could benefit from something very vaguely similar" - then you'd be absolutely spot on!
Right then, say some ref-type is allocated. Would it be possible to attempt figuring out lifetime ownership of the object, and - if a clear ownership can be determined - exclude this allocation from regular GC to instead de-allocate deterministically once (implicitly) released by the owner?
Let's pencil out an example for clarity:
Example 1
When
obj
is allocated, we can assume the local scope ofexample
has ownership of the object.When
DoSomethingWith
is called, it'd take an analysis of the actual implementation of DoSomethingWith() to figure out what happens to ownership here.DoSomethingWith()
, we can assume obj is passed as a borrowed ref. Which in turn means, once the call concludes, ownership transfers back to the caller - and in this case,example()
could release the object at the end of the function callexample
doesn't useobj
anymore after the call toDoSomethingWith
(e.g. we comment out theConsole.WriteLine
-part) , we could assume thatDoSomethingWith
takes full ownership ofobj
. What exactly that means in terms of deallocation would similarly depend on an analysis ofDoSomethingWith
This probably gets trickier once async/await is involved; presumably, in case 1, I imagine you could still consider the reference borrowed if
DoSomethingWith
was async, but the call is awaited.Example 2
This is probably a whole lot harder in terms of analysis, but in theory - if
DoSomethingWith
in this example is always called with ownership ofobj
, then_state = obj
could potentially de-allocate the prior value of_state
when called.Added complexity of course is that it might still need to be GC'ed in case the instance of
Example
itself is deallocated/collected.In a purely internal call chain, I'd assume this type of analysis could maybe be done at compile time; for everything else, I'd guess it'd be more of a JIT-task.
While it's rather hard to guess what the practical impact would - anecdotally, a very significant allocations in the codebases I personally tend to work with come from call chains in which in theory there would seem to be a relatively clear path/transfer of ownership.
Think of your classic ASP.NET or GRPC service: Some service receives a web/grpc request, fetches a bunch of data, does a bunch of transformations, funnels it back into an http or grpc response - I think most of that does not entail any form of shared ownership, so I suspect the vast majority of allocations created in such a pipeline could possibly be de-allocated deterministically with sufficiently good flow analysis.
Of course, it's an extremely.. not very fleshed out idea, so I'd be curious - are there any theoretical reasons why this wouldn't work? If not, how feasible or unfeasible would this be in practice?
There have been plenty of prior prior debate around escape analysis in order to avoid heap allocations - there's probably a degree of overlap here; though die idea above would aim more towards (some) deterministic deallocations in general, rather than heap vs. stack allocations specifically. Though I'd imagine ownership analysis would likely be a superset of escape analysis, and thereby could probably also used to stack-allocate some reference types in these scenarios.
Beta Was this translation helpful? Give feedback.
All reactions