In the future if I need to write automated tests to identify memory leaks I will look into automating the Dev Tools rather than fumbling with WeakMap or performance.memory.usedJSHeapSize
I left some annotations in a comment. Hope it helps!
The API is documented here:. https://chromedevtools.github.io/devtools-protocol/
 Of course, because Lua supports finalizers it's possible to detect GC without using ephemeron tables. But if you can't control the target object's finalizer, then ephemeron tables are handy for doing this. And you can use your own finalizer on the ephemeron table value object to detect GC, though it'll trigger one or two GC cycles behind when the key was collected.
Note that this is somewhat different from a language like Lua where it isn't necessary for all existing script to work with every new iteration of the runtime without any changes.
The fact that implementation details like GC timing have remained behind the veil of abstraction is one of the only reasons that JS engines have managed to evolve from being relatively slow interpreters to highly optimised JIT compilers.
Of course, relying on ephemerons to merely detect GC collection (as opposed to their primary purpose of caching and memoizing data associated to a particular blackbox object instance) is a rather obtuse hack, and not something I've seen in practice for anything other than debugging.
I do agree that it's problematic to rely on certain aspects of a GC, like absolute timing in the case of mark & sweep style GC. But other aspects, like finalizers and object revival, are deliberate guarantees focused on language semantics. Another guarantee that Lua provides is that objects are destroyed in reverse order of creation, which is a useful guarantee from the perspective of a C module writer. Again, because of the nature of the Lua C API and the need to provide more than just a blackbox GC, Lua is far more deliberate about which aspects of the GC can be relied upon (and how), and which aren't their problem. Other languages avoid this--the very thought of providing any GC-specific language features is anathema--but in time invariably find themselves providing ad hoc guarantees and interfaces, or locked into accidental semantics.
Most multimedia in the web is hardware accelerated, SIMD accelerated via plugins or uses Wasm.
Any other way would be a huge waste on resources or simply impossible to do for high resolutions.
Lua has accumulated so many sophisticated constructs because it's a tiny VM that is substantially rewritten with each new major version (5.1 -> 5.2 is a major version bump). And Lua isn't beholden to a strong backward compatibility guarantee; they can discard things that don't work, keeping the VM relatively simple and small and thus easier to refactor. It's notable that while LuaJIT is much faster than PUC Lua, LuaJIT is stuck at 5.1 + some 5.2 extensions. Most newer constructs and semantics added to PUC Lua since 5.1 are relatively difficult to add back into LuaJIT.
In a context of js/lj, lj is a single-variant of always compatible language, which I think shares more similarities with js in this regard, rather than with lua 5.x series.
It's not observable from content, but the Firefox profiler is awesome. Check out https://profiler.firefox.com/docs/#/./memory-allocations
The author's solution proves their point about WeakMap but I don't see how I would use it to practically detect memory leaks in my own programs.
Use the profiling tools to figure out where your memory leaks exist. Doing it in code has a lot of negative consequences. Weak maps and sets, for example, will slow down your GC.
The typical usage of Weak maps and sets is for caching. This allows the GC to give itself extra room on the heap at the expense of potentially another round trip or new calculation.
I run a massive Node application and never had any issues with memory leaks. I wouldn't even know how to forcefully create one even if I wanted to.
I just code and never think twice about GC. How do people end up in situations where they need to start using stuff like WeakMaps?
A simple python memory leak:
a = get_a_huge_object()
# a function that takes long
# that does not use a, but allocates more resources
# get_huge_object() returns a context manager
# it deallocates at the end
with get_huge_object() as a:
a = get_a_huge_object()
Memory leak has a specific meaning. A memory leak is memory that is been allocated but cannot be accessed and deallocate anymore. How useful is that memory is not important. The Wikipedia article explains it much better than myself: https://en.m.wikipedia.org/wiki/Memory_leak
There are useful definition of memory leak, some software need to run for a very long time, they cannot leak memory.
In languages where the memory is automatically managed it is quite hard to generate a memory leak.
Indeed is the original article that simply used a wrong terminology.
If you got more questions let me know! Happy to help!
(1) Analyzing your program's minimum asymptotic resource need
(2) Observing your program's real asymptotic resource need
(3) Optimizing your program in a way (2) is closer to (1)
We had problems with compilers having memory leak. The software I write, runs for weeks or even months without being restarted. Yeah, the original problem of memory leak, or even resources leaks in general is still very very real in some field.
> First and foremost, the problem the original definition points out doesn't exist any more. When a program dies, all the resources it allocated, file descriptors, memory, ports etc will safely be cleaned by the OS. Any modern OS that doesn't do so will consider this a bug. So there is no practical reason to sweat the original problem.
Memory leak never concerns the OS, like never. When the OS allocate memory to a software then is the software responsibility to deallocate it, returning it to the OS.
> Any modern OS that doesn't do so will consider this a bug.
This is true but it is not what we are discussing.
Anyhow, I am just trying to help you understand what people usually means with "memory leak" because you seems a little confused.
But if you are sure and you are definitely not confused and you think that it is me being wrong, I am not going to engage in any discussion.
That's like saying: "I run my program and it works, how can I have bugs??"
Unless you know how to properly test, of course you won't be able to find memory leaks and memory usage will stay the same. Do you click the same thing 5000 times and observe every time memory is cleaned? Do you have unittests against this?
> Do you click the same thing 5000 times and observe every time memory is cleaned?
I don't know how to check that but not sure I understand. If it really was a memory leak the hundred of requests a second I get would surely make the app consume the whole server's memory eventually. I don't need to click stuff 5000 times to test that. It's happening in production as we speak. Just to clarify, it's a single-threaded Node process and its memory consumption has stayed the same for weeks, since the last time I restarted it.
So the UI has a button to start a use case. Each time the user goes into the use case a new object is created which on construction registers a callback against an event type with the event aggregator.
The memory leak occurs if this callback is never de-registered on completion of the use case, since the callback is holding onto a reference to the new object created at initiation of the use case.
If the use case is called repeatedly (think something like a check-in terminal), eventually the memory is exhausted.
On backends I’ve only ever worried about potential memory exhaustion from things like unbounded caches.
It's not a good design. I've been trying to get buy in on using an LRU cache...
Also, I've worked in a few environments (Java and Node) where a spike of requests come into the system and prevent the GC from running - and then you run out of memory. I think that mostly went away with G1. We had a lot of stuff that ran on our customers sites and was prone to traffic spikes...
I've learned that if you're not thinking about GC it usually bites you later. Better to think about performance, at least a little, up front.
Just search the React and Angular GitHub issues for "memory leak".
(1) I have no leaks and (2) I don't know how to create them -- These don't really square with each other.
Leaks are easy. TFA mentions the classic one in UI apps: when you don't remove event listeners.
If he runs his service for a long time and the memory usage doesn't keep growing, no resource exhaustion problem occurs, then he can reasonably say he has no leaks. At least, he has no significant leaks.
I don't have to know how to create nuclear bomb to know I don't have one.
For the authors use case this seems like it would work, since they mention it is part of their test suite
WeakMaps (ephemeron tables) were designed specifically to make garbage collection not be observable, for the reasons jgraham described above.
If you really want to know, such as for testing, then WeakRef and FinalizationRegistry are the newer ways to do this. But know that if your app needs this stuff as part of its normal functioning, then there's at least a 90% chance you're doing something wrong. The GC does not run because you think it should run. If anything, it tries to not run, as much as possible. And the more we optimize it, the better it will get at not running. "Running slow code" is worse than "running fast code" is worse than "not running code at all".
(source: I work on the SpiderMonkey GC engine.)
Chrome's devtools kind of work, but it's not nearly as good.
I'd love to be able to see how many objects exist with a certain signature, or prototype. I found some mdb_v8 thing but it seems it's built for a very old version of V8.
What's happened is not a memory leak, it was an unregistered event handler. These are best diagnosed with profilers, not gymnastics with weak references. (It's not a memory leak because there is still a valid reference through the event handler, ie, no lost pointer.)
If you have a function which each time inadvertently creates a new object in memory which it never de-references (thus is never GC’d), repeated use of the function will ultimately result in memory exhaustion and termination of the process.
Everyone I’ve ever met would refer to that as a memory leak.
But it's not that either. If it were that, and your key died but your map didn't, then the value would still be kept alive. And it doesn't hold both key and value weakly; in that case, you could have both map and key alive and yet the value could die; WeakMaps won't allow that.
It's something subtly different. It's a collection where both the key and map have to be live for the WeakMap entry to keep the value alive. "Weak" in the name is something of a misnomer, in my opinion. Weak normally means "something that can refer to an object without keeping it alive". WeakMap entries are not weak, they are normal strong references that very much keep their values alive -- but only if both the map and key are both alive.
I assume if/when a WeakRef is exposed in the language then a normal map can be used to store id->WeakRef(obj), so no real need them for also having a “mapWithWeakRefValues”?
One common use is to associate extra data with objects, without attaching it to those objects directly. In your map, you add an obj->extradata mapping. Having the target be a WeakRef would just mean you'd lose your extradata while the source obj is still around.