What can happen if I use IdDict to protect an immutable variable from GC deallocation?

Hi,

I am following this link to use IdDict to protect some scalar (immutable, i.e. a=2.0) variables.

https://docs.julialang.org/en/v1/manual/embedding/#Memory-Management

Quote:

One simple way to accomplish this is to use a global IdDict that will hold the references, avoiding deallocation by the GC. However, this method will only work properly with mutable types.

The last sentence said that “this method will only work properly with mutable types”. I ignored this warning and added a scalar (immutable) to IdDict regardless. Everything seems to work fine in this simple example:

#include <stdlib.h>
#include <julia.h>

int main(void) {
    jl_init();
    // gc protect
    jl_value_t * refs = jl_eval_string("refs = IdDict()");
    jl_function_t * setindex = jl_get_function(jl_base_module, "setindex!");
    jl_datatype_t* reft = (jl_datatype_t*)jl_eval_string("Base.RefValue{Any}");

    jl_value_t * a = jl_eval_string("[1.0,2.0,3.0,4.0]");
    jl_call3(setindex, refs, a, a);
    jl_value_t * b = jl_box_float64(0.0001);
    jl_call3(setindex, refs, b, b);

    jl_function_t * print = jl_get_function(jl_base_module, "show");
    jl_function_t * vcat = jl_get_function(jl_base_module, "vcat");

    printf("print a:\n");
    jl_call1(print, (jl_value_t *)a);
    printf("\n");
    printf("print b:\n");
    jl_call1(print, b);
    printf("\n");

    jl_value_t * c = jl_call2(vcat, (jl_value_t *)a, (jl_value_t *)b);
    jl_call3(setindex, refs, c, c);
    printf("print vcat(a, b):\n");
    jl_call1(print, c);
    printf("\n");

    jl_atexit_hook(0);
    return 0;
}

Its output is

print a:
[1.0, 2.0, 3.0, 4.0]
print b:
0.0001
print vcat(a, b):
[1.0, 2.0, 3.0, 4.0, 0.0001]

So did anyone use IdDict to protect a scalar and have some bad results? Any information will be appreciated.

Thanks,
Xinping

The problem is when you set the immutable value in the Dict Julia is actually saving a copy of the value. This means the b might still be deallocated on you. You could create a RefValue{Float64} and save THAT into the Dict. That will keep the value from being deallocated however to get the value you would need to call getindex() on on the RefValue.

1 Like

Thank you very much.