Memory allocation - identical objects

@with_kw struct Currency_Pair
    c1::String3
    c2::String3
    id = c1 * c2
    #other fields derived from c1 and c2 (not involving arrays)
end

x1 = Currency_Pair(c1="AUD",c2="USD")
x2 = Currency_Pair(c1="AUD",c2="USD")

x1 === x2  #true

My code might create the AUD/USD Currency_Pair 1000 times.
I thougt I could save memory by creating a dictionary of Currency_Pair objects and pointing to each one when needed (instead of re-creating it)
But given that x1 === x2, is the code doing this anyway?

i.e is there no difference between creating a new AUD/USD pair and pointing to an existing one.

When you construct a mutable instance twice, you get semantically different instances. A mutable instance is designed for variables to share it and its changes, so since you can make a change to one instance instead of another, they must be considered separate. A mutable instance assigned to multiple variables is implemented by multiple pointers to the same memory address, which is usually on the heap but might be on the stack if the instance has a fixed size and is proven to not need garbage collection.

Incapable of such changes, immutable instances with the same value are semantically the same instance, even though they are usually implemented as many copies in memory. Each copy may take more memory than a pointer (8 bytes on 64-bit systems), but it’s more efficient to reduce pointer dereferencing, heap allocations, and garbage collection.

If you really want to save memory with pointers, you could reuse a few unique mutable instances on the heap (no copies) or a few unique mutable Ref containing immutable instances; you have to be careful not to construct new mutable instances or Ref if the value already exists. You can also mimick pointers without any mutability by mapping integers to unique immutable instances and storing the integers in collections instead of those instances, and you can make that integer as small as you need if you know an upper limit to the number of unique instances; converting from integer to instance is basically the same purpose as dereferencing.

But unless you’re storing a massive collection that threatens to crash the process, I wouldn’t do any of this. For example, if you are constructing 1 isbits immutable instance (isbits means not containing anything that needs pointers) and assigning it to a variable in each iteration of a loop, it just reuses the memory of 1 instance on the stack.

1 Like

Thanks for this.