Solidity – Why Solidity Never Frees Memory: Understanding the Mechanism

memorysolidity

I was reading Solidity's Layout in Memory docs, and I was rather surprised to learn that:

Solidity always places new objects at the free memory pointer and memory is never freed (this might change in the future).

I'm confused. Doesn't memory get flushed across contracts? Say you have an upgradeable proxy that delegate calls to an implementation contract. In this case, we use the "returndatasize" and "returndatacopy" EVM instructions to get hold of the return data. Aren't we doing that precisely because there is no other way to access the return data?

Furthermore, from the same doc:

There are some operations in Solidity that need a temporary memory area larger than 64 bytes and therefore will not fit into the scratch space. They will be placed where the free memory points to, but given their short lifetime, the pointer is not updated. The memory may or may not be zeroed out. Because of this, one should not expect the free memory to point to zeroed out memory.

So which one is it? Does Solidity free memory or not?

Best Answer

Solidity always places new objects at the free memory pointer and memory is never freed (this might change in the future).

This means simply that memory management in Solidity is currently very rudimentary. The compiler maintains a pointer to the end of the last allocated block and that's it. Allocating a new memory variable means moving that pointer forward.

The compiler never tries to reclaim already allocated memory. Even when all references to your memory variable go out of scope, there's no mechanism that would detect it and mark the space as available for reuse.

This is true for the duration of a single external call to the contract. Each new call starts with zeroed memory and freshly initialized free memory pointer.

There are some operations in Solidity that need a temporary memory area larger than 64 bytes and therefore will not fit into the scratch space. They will be placed where the free memory points to, but given their short lifetime, the pointer is not updated. The memory may or may not be zeroed out. Because of this, one should not expect the free memory to point to zeroed out memory.

This part refers to a small optimization the compiler performs when it needs a very short-lived memory block for the current operation. Instead of properly allocating it by updating the free memory pointer, it just writes past the pointer, knowing that the memory there is not in use. The text warns you that if you try to read from this area of unallocated memory using inline assembly, you might find some leftovers from such an operation and you should not assume that the memory there is always zeroed-out.

Related Topic