Hmm, I never thought I'd resurrect something I wrote 20 years ago in Safe, Efficient Garbage Collection for C++:
Weak pointers allow a class to track which objects are being used by other parts of the program. The collector ignores weak pointers when tracing reachable objects, so a weak pointer to an object won't prevent the object from getting collected. The most common use of weak pointers is to build caches of objects in which cached objects are automatically deleted by the collector when clients no longer reference them. In contrast to the traditional way of implementing such caches, clients of weak-pointer caches need not tell the caches when they are finished using an object.
For example, suppose a window server contains a cache of in-memory fonts, keyed by font name. Fonts consume a lot of memory, so when clients of the window server no longer reference a font, it should be deleted automatically from the cache, without requiring notification from clients.
But more usefully, have you seen this chapter in "Programming in Lua"? It gives a better introduction than I can.
With respect to when the garbage collector run, in general I think you should assume it could run at any time.
I understand the general principles, just wondering how to apply in plugins.
What prompted the question:
There are a number of plugins which have caches of keywords, publish service info, etc. - stuff that takes a while to gather up, and will become stale after a while, but keeping it fresh all the time would require excessive resources. So far my solution has been to either make the executive decision (and force user to wait or whatever), or off-load the decision to the user (you wanna run with the stale stuff, or freshen..). Or have a background task to constantly freshen..
I'm wondering if there is some way to make use of weak tables to allow stuff to gracefully expire if unused for a while, but not expire too quickly...
I really haven't thought this through all the way - I've read the chapter in "Programming in Lua" a few times now, but I still haven't figured out how to make use yet, in my own plugins.
I am curious if anybody is actually using weak tables in their plugin(s), and if so could illuminate the value over other alternatives. - maybe give me some fodder for the brainstorm...
Here's a typical scenario for using weak references: A class maintains a cache of resource-intensive objects, each object having some kind of name (e.g. a text label) that can be used to retrieve the object. For example, the objects might consume a lot of memory, or they might be stored persistently on disk and take time to load, or they mirror an object stored on a remote server. The class doesn't want to keep too many of the objects around, since they consume resources (e.g. memory, operating-system handles, remote server resources). But it wants to maintain the invariant that for a given name, at most one instance of that name is loaded at a time.
The traditional solution to this problem is for the class to maintain a reference count on each cache entry, and clients of the cache are responsible for incrementing and decrementing the reference counts in some way. In large systems, this is error prone, just like manual memory management.
Weak references eliminate the need for the clients to maintain the reference counts. When the clients drop all references to an object, the collector eventually sets the corresponding weak reference to nil, and the object is effectively dropped from the cache.
A downside of using weak references is that the class doesn't get much control over how many currently unused objects are maintained in the cache -- as soon as the collector detects an object has no strong references, it immediately sets the weak references to nil and the object gets dropped from the cache. With a little effort, the class could implement a most-recently used policy that maintains in memory the n most-recently used objects, and lets all the other objects get dropped when clients are no longer using them. With more effort, the class could implement a policy that lets objects get dropped no earlier than 30 seconds after their last use.
Several of my plugins maintain caches of things that are relatively expensive to retrieve via the SDK API: keywords and their attributes, folders, collections, the results of catalog:find(). But I haven't perceived the need to use weak references, for a few reasons:
- The memory usage of my plugins doesn't seem excessive (but I haven't looked that carefully at their usage).
- Only one of the plugins, Any Tag, maintains a cache (of keywords) persistently between invocations, and its memory usage doesn't seem noticeable. Any Tag goes to some extreme (and painful) lengths to maintain consistency between its cache of keywords and the "truth" as revealed by the SDK API; I don't think weak references would help maintain that consistency. The other plugins drop most of their cached resources after each invocation. E.g. Any Filter maintains a "memoized" cache of the results of calling catalog:find() to retrieve image attributes that can't be discovered any other way; this cache can get pretty large, but it's dropped immediately when the plugin menu command terminates.
- There is typically only one client of a cache in a plugin, another module within the plugin. So it isn't a programming challenge to track when entries in a cache should be dropped. (If the cache had many clients, then there would be a stronger argument to use weak references.)
Thanks again John - that all makes sense.
I guess I need to cogitate some more on how to keep info up to date. I think ideally there would be a way to be notified, e.g. when user adds a keyword (or as you've mentioned before - just more efficient ways to retrieve periodically..), but given the amount of effort Adobe has invested in the SDK lately, I have low expectations for such improvement.
On the other hand, it's an order of magnitude faster now to reinitialize keyword data now than it was in Lr3 (and Lr2), so perhaps I shouldn't lose all hope, the SDK is not dead, it's just not receiving as much attention as some of us would like.