<p>Modern operating systems usually use some of the main memory for caching files, as loading those files from the cache will be faster than loading them from disk; but this memory can be reclaimed by the OS any time it is needed for something else. The principle is: as long as that memory is spare, you might as well use it for something.</p>
<p>In software, too, caches are often used for data which could be reloaded or recomputed if the cache were cleared. In order to avoid memory leaks, caches may use weak references to allow memory to be reclaimed when there are no more strong references to it. However, for use cases like above, weak references allow objects to be freed too early: in our case, we want cached objects to stay alive until the memory is needed for something else.</p>
<p>I don't know of any terminology for references which behave like this, so for the purposes of this question, I'll call them &quot;semi-weak references&quot;. So a semi-weak reference is sufficient to keep the referenced object alive in a normal GC run, but still allows the object to be freed when the GC is invoked because of an out-of-memory condition (or perhaps some external signal asking the program to try to use less memory). Since the GC needs to behave differently depending on the reason it was invoked, this doesn't seem to be something that could be implemented purely in user code in an ordinary language.</p>
<p>Are there any languages which provide semi-weak references, or some means for users to implement them? If so, what is their specified behaviour?</p>

<memory-management><garbage-collection><weak-references>
A kind of "weak reference" which keeps the object alive, as long as there is otherwise-unused memory
CC BY-SA 4.0
2024-11-19T20:40:34.497Z
You seem to assume that weak references always have a policy of being collected as early as possible, but I don't know if that's true. Maybe your semi-weak references are how normal weak references behave in some languages. Is this equivalent to asking, are there weak references API that lets the user finely configure how aggressively they are collected?
Eldritch Conundrum
CC BY-SA 4.0
2024-11-20T19:02:34.990Z
@EldritchConundrum I don't assume that there is such a policy, only that objects only reachable through weakrefs aren't guaranteed to be kept around much longer, and probably won't be retained indefinitely even if there is no pressure on the allocator. My question is more about specified behaviour than actual behaviour, and certainly weakrefs are not specified to behave like semiweakrefs, even if that behaviour would be consistent with the spec for a weakref. I'm also not looking for fine-grained control.
kaya3
CC BY-SA 4.0
2024-11-21T04:53:12.033Z
The OS paging equivalent of this is Linux's `madvise(MADV_FREE)`. (https://man7.org/linux/man-pages/man2/madvise.2.html)  Although that *doesn't* bias towards keeping the page alive when there's only light memory pressure, more like a lazy `mmap(MAP_FIXED)` to eventually make the page not backed by anything until it's touched again.
Peter Cordes
CC BY-SA 4.0
2024-11-21T13:33:44.070Z
So, from the POV of the program in isolation, weak and semi-weak references are the same (no guarantees). When you expand POV to the whole system they differ. So let's consider "observable behaviour" carefully when answering the question, right?
Pablo H
CC BY-SA 4.0
2024-11-21T16:22:38.337Z
This is closely related to “full laziness” avoidance in lazy evaluators, and “rematerialisation” in register allocators—eliminating common subexpressions saves time, but increases memory pressure, so it can be cheaper to recompute a value than to store & reload it
Jon Purdy
CC BY-SA 4.0
2024-11-21T21:49:52.523Z
Aside from `MADV_FREE` as mentioned by @PeterCordes, you may additionally be interested in the concept of ‘transcendent memory’ (also known as tmem) as provided by the Xen Hypervisor. The idea is that a guest domain can store stuff in tmem that it may want later, but does not need a guarantee that it will still be around later, with the implementation being essentially an LRU cache shared across domains by the hypervisor. Linux has drivers that let it use this for both VFS cache and caching swapped out pages (backed by actual swap of course).
Austin Hemmelgarn
CC BY-SA 4.0
2024-11-23T18:58:13.090Z
FWIW, some terminology: Apple systems ([past](https://archive.org/details/IIgs_2523051_Running_Out_of_Memory/mode/2up) and present) call this type of memory allocation “purgeable”.
Kevin Reid
<p>In</p>
<blockquote>
<p>we want cached objects to stay alive until the memory is needed for
something else</p>
</blockquote>
<p>the difficult point is defining what &quot;needed for something else&quot; exactly means.</p>
<p>If you take it very literally, on machines with virtual memory, &quot;something else&quot; will almost never &quot;need&quot; the memory occupied by your weak references, as it can almost always get additional (virtual) memory from the OS. But that produces an undesirable situation of ever-growing virtual memory, where the system performance will suffer heavily from swapping.</p>
<p>Typical memory-managed runtime systems (like the Java JVM or the .NET runtime) have their own elaborate strategy for deciding when to clear a weak reference. They do not define exactly when this will happen, and this is for good reason, as it allows for many kinds of strategy improvement.</p>

CC BY-SA 4.0
2024-11-20T08:20:34.947Z
2024-11-20T08:20:34.947Z
Ralf Kleberhoff
CC BY-SA 4.0
2024-11-20T18:58:04.727Z
Well, the idea is that the language implementation might choose to free such objects before it requests more memory from the OS. In theory, it could also be possible for an OS to signal to the program that memory is in short supply so please could it free anything it doesn't still need, but I don't know of any OS which does that.
kaya3
CC BY-SA 4.0
2024-11-21T15:25:17.157Z
@kaya3 not really possible on systems that default to overcommit (such as linux and relatives).
Dan M.
CC BY-SA 4.0
2024-11-21T21:53:28.020Z
A reasonable proxy for "when needed for something else" would be "when keeping it would make it necessary to swap something out to disk".  If e.g. an application cache holds some data from a read-only file, the forst of jetissoning that information and later using it would be the cost of reading it from disk, which would be lower than the cost of having to write the contents of a memory block to disk and then later having to read it back.
supercat
CC BY-SA 4.0
2024-12-30T22:22:47.493Z
@supercat A difficulty with that is that swapping to disk is usually transparent to user-mode code. Do any of the common operating systems provide hooks so that user libraries are informed when some of its memory will be swapped out?
Barmar
CC BY-SA 4.0
2024-12-31T17:36:21.130Z
@Barmar: I don't know what features exist in Linux, but I can't see how GC managed frameworks could work well on an OS that couldn't provide some insight about memory usage and availability beyond letting programs allocate memory until the out-of-memory killer kicks in.
supercat
CC BY-SA 4.0
2024-12-31T17:37:59.210Z
@supercat I think they likely use statically-configured memory limits to trigger GC.
Barmar
CC BY-SA 4.0
2024-12-31T17:40:12.683Z
@supercat In particular, if it's a copying GC, you can't wait until `malloc()` fails, because you won't be able to allocate newspace.
Barmar
<p>I've implemented such a cache in a RAII language before and I used an array with a max length of strong (shared) pointers to act as a LRU cache for the cached lookups. Each time a weak pointer gets queried it will update the entry in the array (or add a new one if the weakpointer is empty).</p>
<p>When the array is full it will overwrite the old entry and let the destructor clear the cache entry.</p>
<p>In this case the limit comes from the array of strong pointers.</p>

CC BY-SA 4.0
2024-11-19T18:06:48.763Z
2024-11-19T18:06:48.763Z
ratchet freak
<h2>Java</h2>
<p>Java calls these references &quot;soft references.&quot; They are implemented in the JDK as <a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/ref/SoftReference.html" rel="nofollow noreferrer"><code>java.lang.ref.SoftReference</code></a>. The following is an excerpt from the <code>SoftReference</code> Javadoc:</p>
<blockquote>
<p>Soft reference objects, which are cleared at the discretion of the garbage collector in response to memory demand. Soft references are most often used to implement memory-sensitive caches.</p>
<p>[…]</p>
<p>All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an <code>OutOfMemoryError</code>. Otherwise no constraints are placed upon the time at which a soft reference will be cleared or the order in which a set of such references to different objects will be cleared. Virtual machine implementations are, however, encouraged to bias against clearing recently-created or recently-used soft references.</p>
<p>Direct instances of this class may be used to implement simple caches; this class or derived subclasses may also be used in larger data structures to implement more sophisticated caches.</p>
</blockquote>

CC BY-SA 4.0
2024-11-19T18:02:02.220Z
2024-12-27T19:04:35.300Z
2024-12-27T19:04:35.300Z
Seggan
CC BY-SA 4.0
2024-11-19T18:05:29.173Z
Nice one. By my reading, the docs don't require the GC to keep the object alive until the memory is needed, but that is probably close to the behaviour in practice.
kaya3
CC BY-SA 4.0
2024-11-19T23:22:13.390Z
How do you make use of the referenced object, without risking that it may be pulled out from under you at any time?  Is there a way to atomically "promote" the soft reference to a hard one?
Nate Eldredge
CC BY-SA 4.0
2024-11-20T00:18:52.663Z
@NateEldredge simply `get()` the object, now it has a hard reference so long as you keep it
Seggan
CC BY-SA 4.0
2024-11-20T22:12:21.910Z
Upon investigation, at least for the OpenJDK implementation ([source](https://github.com/openjdk/jdk/blob/b9bf447209db5d7f6bb16a0310421dbe4170500c/src/hotspot/share/gc/shared/referencePolicy.cpp#L43), [search](https://github.com/search?q=repo%3Aopenjdk%2Fjdk+SoftReference+NOT+language%3Ajava&type=code)), it looks like `SoftReference` instances are retained based on recency of access, rather than availability of memory. They are definitely cleared when OOM is about to happen, still.
kaya3
CC BY-SA 4.0
2024-11-20T22:51:38.053Z
@kaya3 Interesting. "They are definitely cleared when OOM is about to happen, still." If that's true, it seems to be rather pointless.  Why not just use weak references? That does, however, align with my recollection of trying (unsuccessfully) to use soft references in Java to implement a memory-sensitive cache in Java using SoftReference.
JimmyJames
CC BY-SA 4.0
2024-11-20T23:37:15.787Z
@JimmyJames they differ from weak references in that they "are cleared at the discretion of the garbage collector in response to memory demand" and "virtual machine implementations are, however, encouraged to bias against clearing recently-created or recently-used soft references."
Seggan
CC BY-SA 4.0
2024-11-21T09:00:31.387Z
FWIW, it appears Ruby also has soft references which likewise are "weakrefs that stay around a bit longer but not necessarily based on memory availability" - [implemented in userland](https://github.com/ruby-concurrency/ref) using Java interop with `java.lang.ref.SoftReference`.
kaya3
CC BY-SA 4.0
2024-11-21T16:20:32.867Z
@Seggan WeakReferences, in my experience, are also cleared in response to memory demand because that's when GC generally runs i.e., when there is demand for free memory in some space of the heap. My expectation when working with SoftReferences was that they would only be cleared when the heap would otherwise need to grow but I couldn't detect any difference between when they were collected and when weak references were collected. Of course, various JVMs could have different approaches but I never found soft references to have practical benefits.
JimmyJames
CC BY-SA 4.0
2024-11-21T17:20:58.853Z
@JimmyJames according to [this SO post](https://stackoverflow.com/a/299702/18162944) "An object which is only weakly reachable (the strongest references to it are WeakReferences) will be discarded at the next garbage collection cycle, but an object which is softly reachable will generally stick around for a while." SO yes they aren't *required* to stick around but the general expectation is that they do.
Seggan
CC BY-SA 4.0
2024-11-21T17:30:09.107Z
@Seggan Right. That *was* my expectation, but it was not met. Soft references were collected just as aggressively as weak ones making them effiectively useless for a memory sensitive cache.  This was many years ago, but I recall being very frustrated and wasting time trying to figure out why soft references were being collected when there was absolutely no need to free the space they were occupying.
JimmyJames
CC BY-SA 4.0
2024-11-21T17:30:54.017Z
@JimmyJames perhaps you were using a nonstandard JVM?
Seggan
CC BY-SA 4.0
2024-11-21T17:39:17.860Z
@Seggan That's a negative, ghost rider. It was hotspot.
JimmyJames
CC BY-SA 4.0
2024-11-21T21:26:10.283Z
@JimmyJames: If the GC can measure the total size of otherwise-unreferenced objects identified via soft references, the amount of storage reclaimed by each "full" GC cycle, and the amount of time spent performing full GC cycles, those figures could together allow an upper-bound estimate of the amount of GC time that could be saved by jetisonning all soft-referenced objects.  It may be hard to quantify how big that value should get before the system nukes soft-referenced objects, but it should be possible to identify many situations where reclaiming the storage wouldn't offer much benefit.
supercat
CC BY-SA 4.0
2024-11-21T21:37:50.223Z
@supercat I see no reason why this couldn't work in any number of useful ways, I'm just describing what behavior I actually saw. I'm not sure what approach was being used to determine when they should be collected, but whatever it was didn't seem to be different from the approach used for weak references. A cache that dumps everything unnecessarily isn't really much of a cache.
JimmyJames
CC BY-SA 4.0
2024-11-21T21:49:54.503Z
@JimmyJames: A real problem, I think, is that languages have evolved to use only memory-management features that operating systems universally support, and operating systems evolved away from efficiently supporting features that applications seldom used.  A Java implementation that tried to use soft references efficiently would appear to use a lot more memory than one which didn't, and be criticized for such memory usage, even if it would adapt itself to use less memory when system memory was tight than when it was plentiful.
supercat
CC BY-SA 4.0
2024-11-21T21:53:31.387Z
@supercat I found this ["Prior to version 1.3.1, the Java HotSpot VMs cleared soft references whenever it found them."](https://www.oracle.com/java/technologies/hotspotfaq.html#gc_softrefs) I didn't think it was that long ago that I tried this but it's possible.  There's also a note about the client VM being more aggressive with soft references than the server so that might have also been in play.  Sorry I can't be more precise here. It was ages ago. Maybe I was too early.
JimmyJames
# A kind of "weak reference" which keeps the object alive, as long as there is otherwise-unused memory
Posted by: username_0 on 2024-11-19
Modern operating systems usually use some of the main memory for caching files, as loading those files from the cache will be faster than loading them from disk; but this memory can be reclaimed by the OS any time it is needed for something else. The principle is: as long as that memory is spare, you might as well use it for something.

In software, too, caches are often used for data which could be reloaded or recomputed if the cache were cleared. In order to avoid memory leaks, caches may use weak references to allow memory to be reclaimed when there are no more strong references to it. However, for use cases like above, weak references allow objects to be freed too early: in our case, we want cached objects to stay alive until the memory is needed for something else.

I don't know of any terminology for references which behave like this, so for the purposes of this question, I'll call them "semi-weak references". So a semi-weak reference is sufficient to keep the referenced object alive in a normal GC run, but still allows the object to be freed when the GC is invoked because of an out-of-memory condition (or perhaps some external signal asking the program to try to use less memory). Since the GC needs to behave differently depending on the reason it was invoked, this doesn't seem to be something that could be implemented purely in user code in an ordinary language.

Are there any languages which provide semi-weak references, or some means for users to implement them? If so, what is their specified behaviour?
**Tags:** memory-management garbage-collection weak-references
> **Comments:**
> **username_1**: You seem to assume that weak references always have a policy of being collected as early as possible, but I don't know if that's true. Maybe your semi-weak references are how normal weak references behave in some languages. Is this equivalent to asking, are there weak references API that lets the user finely configure how aggressively they are collected?  
> **username_0**: @EldritchConundrum I don't assume that there is such a policy, only that objects only reachable through weakrefs aren't guaranteed to be kept around much longer, and probably won't be retained indefinitely even if there is no pressure on the allocator. My question is more about specified behaviour than actual behaviour, and certainly weakrefs are not specified to behave like semiweakrefs, even if that behaviour would be consistent with the spec for a weakref. I'm also not looking for fine-grained control.  
> **username_2**: The OS paging equivalent of this is Linux's `madvise(MADV_FREE)`. (https://man7.org/linux/man-pages/man2/madvise.2.html)  Although that *doesn't* bias towards keeping the page alive when there's only light memory pressure, more like a lazy `mmap(MAP_FIXED)` to eventually make the page not backed by anything until it's touched again.  
> **username_3**: So, from the POV of the program in isolation, weak and semi-weak references are the same (no guarantees). When you expand POV to the whole system they differ. So let's consider "observable behaviour" carefully when answering the question, right?  
> **username_4**: This is closely related to “full laziness” avoidance in lazy evaluators, and “rematerialisation” in register allocators—eliminating common subexpressions saves time, but increases memory pressure, so it can be cheaper to recompute a value than to store & reload it  
> **username_5**: Aside from `MADV_FREE` as mentioned by @PeterCordes, you may additionally be interested in the concept of ‘transcendent memory’ (also known as tmem) as provided by the Xen Hypervisor. The idea is that a guest domain can store stuff in tmem that it may want later, but does not need a guarantee that it will still be around later, with the implementation being essentially an LRU cache shared across domains by the hypervisor. Linux has drivers that let it use this for both VFS cache and caching swapped out pages (backed by actual swap of course).  
> **username_6**: FWIW, some terminology: Apple systems ([past](https://archive.org/details/IIgs_2523051_Running_Out_of_Memory/mode/2up) and present) call this type of memory allocation “purgeable”.  
---
## 3 answers
### Answer by username_12 on 2024-11-19. Score: 25
## Java

Java calls these references "soft references." They are implemented in the JDK as [`java.lang.ref.SoftReference`](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/ref/SoftReference.html). The following is an excerpt from the `SoftReference` Javadoc:

> Soft reference objects, which are cleared at the discretion of the garbage collector in response to memory demand. Soft references are most often used to implement memory-sensitive caches.
>
> […]
>
> All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an `OutOfMemoryError`. Otherwise no constraints are placed upon the time at which a soft reference will be cleared or the order in which a set of such references to different objects will be cleared. Virtual machine implementations are, however, encouraged to bias against clearing recently-created or recently-used soft references.
>
> Direct instances of this class may be used to implement simple caches; this class or derived subclasses may also be used in larger data structures to implement more sophisticated caches.
> **Comments:**
> **username_0** (2024-11-19): Nice one. By my reading, the docs don't require the GC to keep the object alive until the memory is needed, but that is probably close to the behaviour in practice.  
> **username_13** (2024-11-19): How do you make use of the referenced object, without risking that it may be pulled out from under you at any time?  Is there a way to atomically "promote" the soft reference to a hard one?  
> **username_12** (2024-11-20): @NateEldredge simply `get()` the object, now it has a hard reference so long as you keep it  
> **username_0** (2024-11-20): Upon investigation, at least for the OpenJDK implementation ([source](https://github.com/openjdk/jdk/blob/b9bf447209db5d7f6bb16a0310421dbe4170500c/src/hotspot/share/gc/shared/referencePolicy.cpp#L43), [search](https://github.com/search?q=repo%3Aopenjdk%2Fjdk+SoftReference+NOT+language%3Ajava&type=code)), it looks like `SoftReference` instances are retained based on recency of access, rather than availability of memory. They are definitely cleared when OOM is about to happen, still.  
> **username_14** (2024-11-20): @kaya3 Interesting. "They are definitely cleared when OOM is about to happen, still." If that's true, it seems to be rather pointless.  Why not just use weak references? That does, however, align with my recollection of trying (unsuccessfully) to use soft references in Java to implement a memory-sensitive cache in Java using SoftReference.  
> **username_12** (2024-11-20): @JimmyJames they differ from weak references in that they "are cleared at the discretion of the garbage collector in response to memory demand" and "virtual machine implementations are, however, encouraged to bias against clearing recently-created or recently-used soft references."  
> **username_0** (2024-11-21): FWIW, it appears Ruby also has soft references which likewise are "weakrefs that stay around a bit longer but not necessarily based on memory availability" - [implemented in userland](https://github.com/ruby-concurrency/ref) using Java interop with `java.lang.ref.SoftReference`.  
> **username_14** (2024-11-21): @Seggan WeakReferences, in my experience, are also cleared in response to memory demand because that's when GC generally runs i.e., when there is demand for free memory in some space of the heap. My expectation when working with SoftReferences was that they would only be cleared when the heap would otherwise need to grow but I couldn't detect any difference between when they were collected and when weak references were collected. Of course, various JVMs could have different approaches but I never found soft references to have practical benefits.  
> **username_12** (2024-11-21): @JimmyJames according to [this SO post](https://stackoverflow.com/a/299702/18162944) "An object which is only weakly reachable (the strongest references to it are WeakReferences) will be discarded at the next garbage collection cycle, but an object which is softly reachable will generally stick around for a while." SO yes they aren't *required* to stick around but the general expectation is that they do.  
> **username_14** (2024-11-21): @Seggan Right. That *was* my expectation, but it was not met. Soft references were collected just as aggressively as weak ones making them effiectively useless for a memory sensitive cache.  This was many years ago, but I recall being very frustrated and wasting time trying to figure out why soft references were being collected when there was absolutely no need to free the space they were occupying.  
> **username_12** (2024-11-21): @JimmyJames perhaps you were using a nonstandard JVM?  
> **username_14** (2024-11-21): @Seggan That's a negative, ghost rider. It was hotspot.  
> **username_9** (2024-11-21): @JimmyJames: If the GC can measure the total size of otherwise-unreferenced objects identified via soft references, the amount of storage reclaimed by each "full" GC cycle, and the amount of time spent performing full GC cycles, those figures could together allow an upper-bound estimate of the amount of GC time that could be saved by jetisonning all soft-referenced objects.  It may be hard to quantify how big that value should get before the system nukes soft-referenced objects, but it should be possible to identify many situations where reclaiming the storage wouldn't offer much benefit.  
> **username_14** (2024-11-21): @supercat I see no reason why this couldn't work in any number of useful ways, I'm just describing what behavior I actually saw. I'm not sure what approach was being used to determine when they should be collected, but whatever it was didn't seem to be different from the approach used for weak references. A cache that dumps everything unnecessarily isn't really much of a cache.  
> **username_9** (2024-11-21): @JimmyJames: A real problem, I think, is that languages have evolved to use only memory-management features that operating systems universally support, and operating systems evolved away from efficiently supporting features that applications seldom used.  A Java implementation that tried to use soft references efficiently would appear to use a lot more memory than one which didn't, and be criticized for such memory usage, even if it would adapt itself to use less memory when system memory was tight than when it was plentiful.  
> **username_14** (2024-11-21): @supercat I found this ["Prior to version 1.3.1, the Java HotSpot VMs cleared soft references whenever it found them."](https://www.oracle.com/java/technologies/hotspotfaq.html#gc_softrefs) I didn't think it was that long ago that I tried this but it's possible.  There's also a note about the client VM being more aggressive with soft references than the server so that might have also been in play.  Sorry I can't be more precise here. It was ages ago. Maybe I was too early.  
---
### Answer by username_7 on 2024-11-20. Score: 6
In

> we want cached objects to stay alive until the memory is needed for
> something else

the difficult point is defining what "needed for something else" exactly means.

If you take it very literally, on machines with virtual memory, "something else" will almost never "need" the memory occupied by your weak references, as it can almost always get additional (virtual) memory from the OS. But that produces an undesirable situation of ever-growing virtual memory, where the system performance will suffer heavily from swapping.

Typical memory-managed runtime systems (like the Java JVM or the .NET runtime) have their own elaborate strategy for deciding when to clear a weak reference. They do not define exactly when this will happen, and this is for good reason, as it allows for many kinds of strategy improvement.
> **Comments:**
> **username_0** (2024-11-20): Well, the idea is that the language implementation might choose to free such objects before it requests more memory from the OS. In theory, it could also be possible for an OS to signal to the program that memory is in short supply so please could it free anything it doesn't still need, but I don't know of any OS which does that.  
> **username_8** (2024-11-21): @kaya3 not really possible on systems that default to overcommit (such as linux and relatives).  
> **username_9** (2024-11-21): A reasonable proxy for "when needed for something else" would be "when keeping it would make it necessary to swap something out to disk".  If e.g. an application cache holds some data from a read-only file, the forst of jetissoning that information and later using it would be the cost of reading it from disk, which would be lower than the cost of having to write the contents of a memory block to disk and then later having to read it back.  
> **username_10** (2024-12-30): @supercat A difficulty with that is that swapping to disk is usually transparent to user-mode code. Do any of the common operating systems provide hooks so that user libraries are informed when some of its memory will be swapped out?  
> **username_9** (2024-12-31): @Barmar: I don't know what features exist in Linux, but I can't see how GC managed frameworks could work well on an OS that couldn't provide some insight about memory usage and availability beyond letting programs allocate memory until the out-of-memory killer kicks in.  
> **username_10** (2024-12-31): @supercat I think they likely use statically-configured memory limits to trigger GC.  
> **username_10** (2024-12-31): @supercat In particular, if it's a copying GC, you can't wait until `malloc()` fails, because you won't be able to allocate newspace.  
---
### Answer by username_11 on 2024-11-19. Score: 3
I've implemented such a cache in a RAII language before and I used an array with a max length of strong (shared) pointers to act as a LRU cache for the cached lookups. Each time a weak pointer gets queried it will update the entry in the array (or add a new one if the weakpointer is empty).

When the array is full it will overwrite the old entry and let the destructor clear the cache entry.

In this case the limit comes from the array of strong pointers.
---
