The hash-table is actually a sparse table, which is extended whenever it is needed. If you have less than 64 values, then one bucket is enough. If you have 70, then you need two buckets. Basically, this sparse table is a table of at most 1024 element tables.
Since variable ids are contiguous, it means that you can fill in this sparse table element by element, only creating new buckets when needed.
So basically, what I'm doing is the following:
id / 64 -> yields the sub-table id % 64 -> yields the position in the sub-table
These operations are very fast since we are dealing with basic binary arithmetic.
I have been dealing with reference counting for years as I have implemented other programming languages in the past (see Tamgu for instance).
I only increment the reference counter in two cases:
a) A value is pushed into a container b) A value is stored in a variable
The fact that containers are classes, with their own methods to store elements makes it very simple to handle these cases. I only decrement the reference counter, when the value is removed from the container or the variable is modified and released.
Now, one of the things I do is that when I push a container A into another container B, I DO NOT modified the references of the elements in A. There are no recursive increments.