Remix.run Logo
▲ nasretdinov 4 hours ago

Unfortunately that's somewhat expected - regardless of implementation, the sole fact that the GC needs to somehow walk the entire tree to trace still referenced sections makes swap highly impractical -- even if you had not had 40ms stop-the-world pauses the LRU cache used by swap would get thrown away at every GC.

I believe that's actually the same reason why Apple stopped using GC in their frameworks in favour of automatic reference counting.

▲renox 3 hours ago | parent | next [-]

> Unfortunately that's somewhat expected - regardless of implementation

Yes, that's expected and no not "regardless of implementation": the GC implementation CAN be improved.

See this discussion on reddit: https://old.reddit.com/r/programming/comments/1wf2fei/40ms_g...

Copy/pasted here: >>

I remember a research paper about swap and GC, where the GC cooperated with the OS to avoid this kind of issue. AFAIK it went nowhere, too bad.

[–]andreiross[S] 15 points il y a 21 jours

Are you talking about this one? https://cse.buffalo.edu/\~mhertz/bc-pldi-2005.pdf. If so, yes. Too bad. I don't know the repercusions this paper had in the past, though, in the sense of pros and cons of the bookmark collector. Don't know if anyone tried to actually implement it or design it at some point.

[–]renozyx 9 points il y a 21 jours

Yes, congratulations for finding it. And I don't know either,. Except that they did implement it on Linux (of course) https://plasma.cs.umass.edu/emery/cooperative-memory-managem...

<<

▲torginus 2 hours ago | parent | prev | next [-]

Modern OSes need a facility to signal to a thread that it hit a paged out chunk of memory. It's not like it's not possible to create a swap-aware GC (or any other kind of code that touches lots of memory).

I would go further - I think the whole swap lifecycle needs to be communicated. Before the OS swaps out a page, if it could invoke the GC which would clean up that piece of memory so that we dont end up writing garbage to swap.

The OS should also allow marking pages as piority to stop them from being swapped out.

▲aktau 2 hours ago | parent [-]

> The OS should also allow marking pages as piority to stop them from being swapped out.

This is IIUC possible using the mlock(2) family of syscalls: https://man7.org/linux/man-pages/man2/mlock.2.html. (On Linux, though I'm guessing other UNIXen and operating systems have it or something equivalent.)

▲torginus 2 hours ago | parent [-]

Cool. So this should be a bug ticket, not irrefutable proof that GCs suck :D

▲pjmlp 3 hours ago | parent | prev | next [-]

Reference counting is a GC algorithm, and no this isn't expected, it depends pretty much on the implementation.

Many make the mistake to think there is only one way to do a GC.

One of the authoritative books on the subject, https://gchandbook.org/contents.html

And a quite well known paper on the matter as well, https://dl.acm.org/doi/10.1145/1035292.1028982

▲adrian_b 2 hours ago | parent | next [-]

Whether reference counting is a GC algorithm depends on how you define what GC is.

I prefer to consider GC only the methods of memory management where reclaiming the no longer used memory is done either asynchronously with the main program or as late as possible, i.e. when new allocation requests cannot be satisfied.

In the normal implementation of reference counting, memory is freed as soon as possible, i.e. exactly like stack memory, when blocks are exited, so I do not consider reference counting as GC.

The problem with GC in the strict sense is that you cannot predict when it will happen. With both stack memory and reference counted heap memory you know that whenever you exit a block, some time will be spent with running destructors and for freeing memory, but such interruptions will not happen in other points of the program.

▲Sesse__ 2 hours ago | parent | next [-]

> Whether reference counting is a GC algorithm depends on how you define what GC is.

Pretty much all the high-performance GC/refcounting algorithms are hybrids in one form or the other; it's a spectrum of choices. https://dl.acm.org/doi/10.1145/1028976.1028982 explores this in some detail.

▲adrian_b an hour ago | parent [-]

That is a classic paper and obviously I am aware of it.

However, if you have distinct names it is efficient to use them with distinct meanings.

Making "garbage collection" synonymous with "freeing memory" is bad, because it eliminates a means to distinguish various methods for freeing memory.

Like I have said, I consider useful to define "garbage collection" as any method of freeing memory where the memory is not freed as soon as possible (i.e. when a block is exited), but freeing is deferred to be performed at a later time, even as late as possible (i.e. when new memory allocation requests cannot be satisfied).

Indeed, many garbage collection algorithms use reference counts, where memory deallocation is deferred, but when I use the term "reference counting" without any other qualifier, I mean it in the sense in which it was originally defined in 1960, where the time when memory deallocation is run is predictable, exactly like for stack-allocated memory.

I prefer to write programs with well-defined worst-case behavior, so I normally prefer deterministic algorithms. Thus I always prefer to use reference counts instead of GC. I have never encountered a case when avoiding reference cycles was difficult.

▲pebal an hour ago | parent | prev | next [-]

> The problem with GC in the strict sense is that you cannot predict when it will happen.

It’s the same with ARC. You also don’t know when the counter will reach zero.

▲adrian_b 36 minutes ago | parent [-]

No, that is not true.

In the normal implementation of reference counts, counters can be decremented only at block exits and not at any other program point.

At a block exit some of the local variables that are freed may contain references, so freeing them will decrement some reference counts. Then some counters will reach zero, triggering other deallocations and the decrementing of other counters. This will repeat until no other counters reach zero.

All the memory deallocation happens predictably, only at block exits.

If a variable is not freed immediately when a counter reaches zero, but the deallocation is deferred for a later time, which is not predictable, that is no longer classic memory management with reference counts, but it is a garbage collector, which happens to also use reference counts, probably in combination with some tracing algorithm.

When reference counts are implemented, manual memory deallocation, like with C free() or C++ delete, should be forbidden, but even if it were used that would just introduce other program points besides the block exits, where it is known that memory deallocation will happen.

▲pjmlp an hour ago | parent | prev [-]

I define the academic view of GC algorithms in Computer Science, not what random developers decide to call GC.

Which in an industry where some folks call themselves Software Engineers after a bootcamp, without any kind of accreditation, I rather stay with the definition from those that do language design and compiler algorithms research.

▲adrian_b an hour ago | parent [-]

I prefer to use the terms as they were originally defined by the authors who introduced them, and not with the modified meanings that become fashionable after the authors of some paper written some decades later decide randomly to change the definitions of the old terms. This is also true for the terms "garbage collector" and "reference counts", which were both introduced in 1960 to denote 2 clearly distinct methods of memory management, and the main difference between them does not consist in whether some kind of reference counts exist somewhere, or not.

The paper "A unified theory of garbage collection", which has started the fashion of considering reference counting as a kind of garbage collection, only shows correctly that both tracing and reference counting are complementary implementation techniques for a garbage collector.

It does not mention anywhere the essential practical difference between the traditional standalone memory management with reference counts and a garbage collector, which stays the same regardless whether the garbage collector also happens to use reference counts for some purposes, which is the difference between predictable and unpredictable times when memory reclamation is done.

Many of the modern authors of academic papers are a poor model of using computer terminology (or for the terminology in other domains), because very frequently it is obvious that they have not read the old works where such terms were introduced for the first time, even when such works are cited in the bibliography.

Unlike them, I have done an extensive research to find when and where various computing terms have been used for the first time, and I strive to use most terms with their original meanings, not with corrupted meanings, even in the cases when the latter have become more popular lately.

▲pjmlp a minute ago | parent [-]

So as fellow digital archaeologist I would find interesting to find Lisp, BASIC, CLU, SIMULA, or Cedar papers, where the authors mention reference counting not being a form of garbage collection algorithms.

Cedar was already combining reference counting with a cycle collector, as one of the very first systems programming languages with automatic resource management.

▲red75prime 2 hours ago | parent | prev | next [-]

You just need to remember that garbage (unreachable reference cycles) isn't collected.

▲ 3 hours ago | parent | prev | next [-]
[deleted]
▲IshKebab 3 hours ago | parent | prev [-]

In common use, GC refers to mark and sweep and similar systems where allocations are not freed at an easy to predict time.

▲pjmlp 2 hours ago | parent [-]

In common use, by those that never learn the theory behind their tools.

That is a tracing GC by the way.

There are also tracing GC implementations with deterministic resource management APIs, .NET and D have them for example.

▲IshKebab an hour ago | parent [-]

People use words in a way that is useful. Really this just shows that the pedantic academic definition of GC is not the most useful one.

▲torginus 2 hours ago | parent | prev | next [-]

The issue described in the article isn't really GC specific. The Go GC has a critical section that reads metadata.

Any program that has a rarely accessed, but vital chunk of memory is vulnerable to this sort of issue.

▲the8472 2 hours ago | parent | prev [-]

A region-based collector like Hotspot's G1 combined with madvise could probably operate in a manner that's more swap-friendly by focusing on a smaller working-set at any given moment and announcing its intent to switch the working set to the OS ahead of time.