This question is newly relevant in light of the new ref locals and ref return features in the latest versions of C# 7:
With the increased prominence and wider use of managed--or "interior"--pointer variables in C#, occasionally you may need to recover the respective containing Pinnable
GC object for such a pointer. For example, if you are passing around a managed pointer to an array element of type T
, you might need the array reference T[]
itself in order to call (e.g.) Array.Copy(...)
.
So, from managed code, is there any reasonably legitimate way to recover the containing GC object handle, given either of the following prevalent interior/managed pointer (
ref
,out
,in
) uses:
struct
or class
) field within a GC object instance;struct
or class
) element T
of Array T[]
.Internally in .NET, it appears that the GC uses the following function: /coreclr/master/src/gc/gc.cpp
#ifdef INTERIOR_POINTERS
// will find all heap objects (large and small)
uint8_t* gc_heap::find_object (uint8_t* interior, uint8_t* low)
{
....
This code walks through known GC heaps checking for whether the specified interior pointer falls within the range of the known GC object allocations. Obviously, this method is not readily accessible from end-user managed code and, for all I know, may not even be relevant if there's no GC in progress.
I also looked through the new Span<T>
and System.Memory
libraries, but couldn't find a sequence of manipulations that would recover an (e.g.) array handle if you didn't start by providing it in the first place (whereby the containing handle gets squirreled away in those various structs). In cases where the _pinnable
is optional (e.g. Span<T>
), the GC handle in the struct is null
, so if you don't opt-in from the start, there's no way to get it back.
Summary: Is there any way to recover the containing object handle from a managed pointer?
[edit:] If the managed pointer points to a value-type on the stack, it would be perfectly reasonable for the (putative) handle recovery function to indicate failure by (e.g.) returning 'null'.
Related: How does the C# garbage collector find objects whose only reference is an interior pointer?
GC checks the below information to check if the object is live: It collects all handles of an object that are allocated by user code or by CLR. Keeps track of static objects, as they are referenced to some other objects. Use stack provided by stack walker and JIT.
NET Framework. Automatic memory management is made possible by Garbage Collection in . NET Framework.
The garbage collector provides the following benefits: Frees developers from having to manually release memory. Allocates objects on the managed heap efficiently. Reclaims objects that are no longer being used, clears their memory, and keeps the memory available for future allocations.
However, if the object requires finalization, the object is considered live again until it is actually finalized, and then it is permanently dead. In other words, an object requiring finalization dies, lives, and then dies again. This is a very interesting phenomenon called resurrection.
No, recovery of the containing object from an interior pointer is not possible. During GC, interior pointers are translated into corresponding objects thanks to the so-called brick table and plug trees. Given a specified address, the proper brick table entry is calculated and corresponding plug tree is traversed to find the plug within which that address lives. Finally, that plug is scanned object-by-object to find the one that contains the considered address.
The point is those trees are built and available only during GC. So, even if such an "interior pointer recovery" API existed, it would have to wait for the GC and could provide an answer only afterwards (which seems very impractical). Other solutions, like linear memory scanning, would obviously possibly introduce tremendous overhead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With