It’s pretty easy to find cases where rooting is necessary, though slightly more tricky to demonstrate very clearly what is going on.
The following is a fairly minimal example:
#include "julia.h"
int main()
{
jl_init();
jl_value_t *x = NULL;
// JL_GC_PUSH1(&x); // Uncomment to remove the segfault
x = jl_eval_string("1.1");
jl_eval_string("GC.gc()"); // Will collect the value pointed to by `x` if you don't root it.
// following will segfault (on my machine) if `x` has been collected
jl_call1(jl_eval_string("println"), x);
jl_atexit_hook(0);
return 0;
}