News for hackers. Stuff that matters.
Re:Modern garbage collection: Part 2 by w0utert on Saturday December 14, 2019 @06:25AM (#21788953)
True. This is why any serious game running on a VM with GC would avoid any kind of per-frame memory allocation and use arena allocators instead.

The whole premise of a GC to save you from thinking about memory allocation is moot if it comes to real-time sensitive tasks, there it makes things harder instead of easier. A reference counting system is much better IMO, even though you may be able to get higher absolute throughput with GC, at least the small overhead you incur is stable and predictable.

Re:Modern garbage collection: Part 2 by _ph_ on Saturday December 14, 2019 @09:07AM (#21789541)
I don't think the idea of GC is to save you from thinking about memory allocation. Actually, not thinking about memory allocation is a great way to create very slow programs, independant of whether you us an GC or manually free memory, though modern GCs keep the performance penalty reasonably low. Still, you want to think about memory allocation, so that you don't allocate inefficiently.

What GC delivers is first of all the guarantee of correctness, a pointer is either nil or points to a validly allocated memory. Also, it removes most needs of bookkeeping. That simplifies programs and especially allows to write clean APIs, where functions are fine to allocate reasonable amounts of memory.

But wherever there are large parts of memory required, especially with a clear lifetime, I think a lot about memory allocation and even in a GC language I try to reuse memory wherever that makes sense.

So for a game engine, there should not be much need for allocation during the run time of a "level" and thus GC pauses should only happen between levels.

Re:Modern garbage collection: Part 2 by barrkel on Saturday December 14, 2019 @11:12AM (#21790189)
Not thinking about ownership over references to heap allocations is very very much the big productivity win from GC. Memory safety is usually an additional bonus, but it's a distinct thing; it's possible to have (conservative or refcounting) GC without memory safety and vice versa.
Re:Modern garbage collection: Part 2 by nwallin on Saturday December 14, 2019 @10:41PM (#21794302)
In my experience it's been the opposite.

We work on a dual C++/C# codebase. Something like 3/4 C++ and 1/4 C#. Basically all of the memory lifetime errors happen in C# land. I do not recall a memory lifetime error _ever_ hitting master in C++, but we have one bug against _prod_ right now and two bugs against master right now, as we speak in C#.

Dealing with lifetimes in C++ is easy, dealing with it in C# is a nightmare. Maybe it's easier in Java or Go, I don't know, I've only dealt with Java in school and never coded in anger in Go.

Re:Modern garbage collection: Part 2 by LessDmesg on Sunday December 15, 2019 @03:30AM (#21795155)
Interesting. Could you give an example of such a memory lifetime bug in C# and why C++ is impervious to it?
Re:Modern garbage collection: Part 2 by nwallin on Monday December 16, 2019 @10:18PM (#21810206)
async factory methods for stuff the API requires me to keep around, but the same API requires my objects to be constructed synchronously. (This includes stuff in .NET) C++ doesn't have async as a language construct. (yet. I dread the day.)

IDispose. We have an ecosystem where a nonnegligible number of in flight objects need to manually be disposed of. In C++, RAII takes care of this for us.

Un listening to events. Needs to happen manually in the standard .NET listeners. C++ solves this with weak_ptr. C# could solve this with a better standard library, but we have .NET.

Honorable mention (not lifetime, but the deadlock quagmire that is C# and its half async half synchronous standard library) is WritableBitmap, which is impossible to use correctly, and has not been deprecated or had a safe replacement offered.

C++ surprises me in ways I expect to be surprised. C# surprises me in ways that leaves me confused and perplexed.

Re:Modern garbage collection: Part 2 by zozbot234 on Saturday December 14, 2019 @11:22AM (#21790260)
> Not thinking about ownership over references to heap allocations is very very much the big productivity win from GC.

I very much doubt that this is a big _productivity_ win. Languages in which it is idiomatic to "think about ownership over heap allocations" (C++, Rust) aren't obviously less productive than comparable languages where such thinking is not so idiomatic (C, Java, .NET, ObjC, Swift etc.).

It's somewhat common to use refcounting (shared_ptr<>, etc.) in the more exploratory style of programming where such "thinking" is entirely incidental, but refactoring the code to introduce proper tracking of ownership is quite straightforward, and not a serious drain on productivity.

Re:Modern garbage collection: Part 2 by brighteyes on Saturday December 14, 2019 @01:42PM (#21791230)
GC might not be a productivity win for you, but for many people it definitely is.

I'm pretty sure that's true for the great majority of software developers, but of course they don't even use a non-GC language!

Part of the reason they don't is that productivity. Not that they chose it personally for that reason, but e.g. historically enterprise code moved to Java and C# for related reasons.

(I also agree there are people that are equally productive in non-GC languages, or even more - different people have different programming styles.)

Re:Modern garbage collection: Part 2 by zozbot234 on Saturday December 14, 2019 @01:58PM (#21791338)
Enterprise code moved to Java (and later C#) for memory safety, period. The level of constant bugginess in the C++ codebases just made them way too messy and outright unmanageable.
Re:Modern garbage collection: Part 2 by adev_ on Saturday December 14, 2019 @02:26PM (#21791553)
Wrong, and definitively not period.

The enterprise world moved to Java and C# because:

- It was a corporate language with corporate support and that matter a lot in many environment.

- It had at the time one of the best ecosystem of tools available.

- It was the mainstream fashion of a time and nobody get fired to buy Sun/IBM/Microsoft right ?

Most companies (and managers) could not less give a dare about your program crashing with a segfault (unsafe) or a null pointer exception (safe). It's the same result for them.

Re:Modern garbage collection: Part 2 by ScottBurson on Saturday December 14, 2019 @03:56PM (#21792190)
> It's the same result for them

Not in a security-related situation, it's not! And to a lesser extent, lack of memory safety also poses a danger of silent memory corruption. (Yes, usually the program will crash outright, but not always.) And it can be a lot harder to debug a crash when it doesn't happen until thousands of cycles after the erroneous access.

Sun and Microsoft wouldn't have built and pushed Java and C# in the first place if there hadn't been a real need for safer languages.

Re:Modern garbage collection: Part 2 by adev_ on Saturday December 14, 2019 @04:15PM (#21792306)
> Sun and Microsoft wouldn't have built and pushed Java and C# in the first place if there hadn't been a real need for safer languages.

Excepted they were safer languages before Java and C#: Ada, Lisp, All the ML family.... And all of them never lift off.

Java and C# have been successful because they were accessible and easy to learn ( partially due to their memory model), not because they were safe.

As a parenthesis, a beautiful side effect of that has also been an entire generation of programmer that has no clue of the memory model their language use underneath, because "it's managed", because it's GC.....without even realising that their 50 Millions nested/mutual object graph will make the GC on its knees on production. With the results we all know today.

Re:Modern garbage collection: Part 2 by renox on Sunday December 15, 2019 @03:21AM (#21795134)
Maybe, but remember that computers were very, very slow and with small memory, so GC's overhead used to be unacceptable (Emacs == eight megabytes and constantly swapping? I've seen it)..

I think that Java came 'at the right time': when computers became fast enough that the GC overhead didn't matter (except where low latency matter).

Re:Modern garbage collection: Part 2 by LessDmesg on Saturday December 14, 2019 @02:41PM (#21791663)
Reference counting is not better, it's a poor man's GC. Reference counting means: 1) instruction pollution from all the refcount updates and their synchronization 2) circular references, ie memory leaks 3) too much time spent freeing memory (whereas a generational GC spends time on live objects only) 4) memory fragmentation and hence slow allocation (whereas in a normal GC allocation is just O(1)
Re:Modern garbage collection: Part 2 by w0utert on Sunday December 15, 2019 @08:15AM (#21796063)
Languages like Swift and Objective-C hide the reference counting for you, so 'instruction pollution' is not really something I care about. The overhead at the instruction & memory level is fairly minimal for these language too, by means of using tagged pointers. I'm pretty sure the compiler is smart enough to factor out reference counting for complete sections where it can determine objects can impossibly go out of scope (e.g. sections where aliasing can be ruled out, and all assignments are to locals, such as in many loops).

Circular references can be a problem, this is just something you have to live with and design for, just as in languages with manual memory management. In the typical cases where this can be a problem (graphs of objects) its very straightforward how to fix them using weak references.

I don't understand point 3 and 4 and why they would be a property of reference counting for memory management. They both seem completely orthogonal problems that have nothing to do with the mechanisms that decide when to free memory.

Anyway, my original point was not that reference counting is perfect, or even more efficient compared to garbage collection. Just that it is predictable and deterministic, which is very often much more important, especially for code with real-time constraints.

Re:Modern garbage collection: Part 2 by liuliu on Monday December 16, 2019 @04:56PM (#21807742)
> Languages like Swift and Objective-C hide the reference counting for you, so 'instruction pollution' is not really something I care about. The overhead at the instruction & memory level is fairly minimal for these language too, by means of using tagged pointers. I'm pretty sure the compiler is smart enough to factor out reference counting for complete sections where it can determine objects can impossibly go out of scope (e.g. sections where aliasing can be ruled out, and all assignments are to locals, such as in many loops).

New Swift Ownership API can help, but compiler is not that good to figure out exclusive ownership all by themselves without any annotation. It is common to have more than 10% of you time in RC environment spent on refcount calculations and locks acquisition (some stats: http://iacoma.cs.uiuc.edu/iacoma-papers/pact18.pdf).

Re:Modern garbage collection: Part 2 by zozbot234 on Sunday December 15, 2019 @08:22AM (#21796094)
> instruction pollution from all the refcount updates and their synchronization

If the language supports ownership tracking and non-synchronized Rc<> as in Rust, refcount updates ought to be rare and/or quick. I agree that this is very much an issue in languages with obligate "managed" memory such as Swift, and that tracing GC may sometimes be preferable to that.

> too much time spent freeing memory

If you're using Rc, you probably care about memory reclaim being deterministic, which tracing GC doesn't give you. You can also use arenas to free a bunch of objects all at once; this also addresses memory fragmentation and slow allocation to some extent.

Re:Modern garbage collection: Part 2 by saagarjha on Saturday December 14, 2019 @06:18PM (#21793073)
> circular references

You can solve this with weak references.

Re:Modern garbage collection: Part 2 by LessDmesg on Sunday December 15, 2019 @03:27AM (#21795145)
...which is manual work with no guarantees of correctness.
Re:Modern garbage collection: Part 2 by ncmncm on Monday December 16, 2019 @12:00AM (#21800911)
But never, in practice, needed, so any downside is only theoretical.
Re:Modern garbage collection: Part 2 by barrkel on Saturday December 14, 2019 @11:09AM (#21790169)
Per-frame allocation would be very cheap with a tuned generational GC run every frame, as nothing would be live at the end of the frame and thus tracing would take almost no time. Of course the same would be true of an arena allocator, at the cost of needing to classify every allocation accurately.
Re:Modern garbage collection: Part 2 by masklinn on Saturday December 14, 2019 @07:41AM (#21789227)
> True. This is why any serious game running on a VM with GC would avoid any kind of per-frame memory allocation and use arena allocators instead.

The problem is having the VM allow and support that usage, and the JVM definitely is not best-of-class there. See ixy[0] from a few months back where the researchers / developers didn't manage to get under

> ~20 bytes of allocation per forwarded packet in Java.

[0] https://github.com/ixy-languages/ixy-languages

Re:Modern garbage collection: Part 2 by enhray on Saturday December 14, 2019 @10:21AM (#21789878)
I’ve heard horror stories about reference counting performance cliffs caused by avalanche deallocations, which are hard to predict.
Re:Modern garbage collection: Part 2 by w0utert on Sunday December 15, 2019 @08:18AM (#21796081)
They are not harder to predict or control than garbage collection, and have the benefit of being completely deterministic. Of course you can always come up with some pathological case that would trigger a 'deallocation avalanche', but you would almost have to deliberately make an effort to run into a thing like that. And if you do, it's typically very easy to fix these kinds of things.

In the Objective-C era before automatic reference counting, you had these things called 'autorelease pools' which allow pretty straightforward control over deallocation. I think the same thing is still possible in ARC Obj-C and Swift.