I’ve seen a little gem pass by in a Go cryptography code review and I want to share it because I think it’s a pattern that can be reused.
Let’s start with a problem statement: crypto/x509 Certificate
values take a bunch of memory, and for every open TLS connection you end up with a copy of the leaf and intermediate certificate, and sometimes of the root too. That’s kind of a waste of memory, a big one if you open a lot of connections to the same endpoint or to endpoints that use the same roots.
Ideally, if there was already a parsed copy of a certificate in memory we’d just return a pointer to that. An easy way to do that would be to have a map[string]*x509.Certificate
somewhere mapping the certificate bytes to the parsed structure, and reuse an old entry if present. This is the concept of interning, usually used for short strings and other commonly repeated immutable values.
The problem is: how do we evict entries from that cache when they aren’t needed anymore? We can’t have a client that connects to a lot of endpoints one after the other just grow its memory usage endlessly.
The “simplest” solution would be to store a reference counter, remember to decrease it when we don’t need the certificate anymore, and delete the entry from the map when it reaches zero. How do we decrement it though? The x509.Certificate
is needed for as long as the tls.Conn
is live, because you can call PeerCertificates
on the Conn
. Any manual way of doing it is guaranteed to turn out wrong, causing memory leaks.
Some languages have the concept of “weak reference” for this: a pointer that points to the thing but doesn’t keep it live.