Nesting a ref-struct
instance within another, one of the properties of the nested object is corrupted upon manual garbage collection.
See this minimal code reproduction: https://github.com/hunterlester/minimum-ref-struct-corruption
Notice on the 3rd line of log output that the value of name
is not corrupted:
Running garbage collection...
authGranted object afte gc: { name: '�_n9a\u0002', 'ref.buffer': <Buffer@0x00000261396F3910 18 86 6c 39 61 02 00 00> }
Unnested access container entry after gc: { name: 'apps/net.maidsafe.examples.mailtutorial', 'ref.buffer': <Buffer@0x00000261396F3B10 60 68 6e 39 61 02 00 00> }
Globally assigned values after gc: apps/net.maidsafe.examples.mailtutorial _publicNames
While
ref
,ref-struct
andref-array
are powerful, but fragile things, their combination can behave really obscure.There are two nuances with your sample:
Calling
makeAccessContainerEntry
twice overwrites your global cache -CStrings
cached (global.x0
andglobal.x1
) during themakeAuthGrantedFfiStruct
call will be overwritten by the second directmakeAccessContainerEntry
call.It seems that you should cache each
ContainerInfoArray
too.This code should work fine:
As you can see, I added cache to
makeAccessContainerEntry
output, you should keep it somewhere as long as you need the data to be held from garbage collection.Edit: some background
JS implements high-level Memory Management where objects are referenced by references and memory gets released whenever there are no more references to the specific object.
In C there are no references and GC, but there are pointers which are simply memory addresses which point to the location where a specific structure or memory block is located.
ref
uses the following technique to bind these two: C pointer is a Buffer which stores the memory address where the actual data is located in memory. Actual data is usually is represented as a Buffer too.ref-struct
is an addon toref
which implements the ability to interpret underlying memory blocks (Buffers) as structures - user defines types and how they are located in memory,ref-struct
attempts to read the corresponding portion of a memory block and obtain the value.ref-array
is an addon toref
which implements the ability to interpret underlying memory blocks (Buffers) as arrays - user defines types and how they are located in memory,ref-array
attempts to read the corresponding portion of a memory block and obtain the array item.This way if you allocate a Buffer for something, then obtain a
ref
reference to it (a new Buffer that simply holds the memory address of the original Buffer) and lose the JS reference to the original Buffer, then the original Buffer could get released by GC like this:Do not hurry to test this code - both
console.log(refReference.deref());
will print the same output becauseref
holds a hidden reference to the referenceddata
in therefReference
.ref-struct
andref-array
are aware of such situations and usually correctly hold hidden references to the referenced data too. But a combination ofref-struct
andref-array
reveals a bug or an underlying incompatibility and hidden references sometimes get lost. A workaround is to cache references by yourself - that is the approach I suggested to use.