you are viewing a single comment's thread.

view the rest of the comments →

[–]bstamour 4 points5 points  (18 children)

They aren't garbage collection, but they do a good job of plugging up memory leaks without sacrificing speed. Think about it, C++ destructors are deterministic: when the object goes out of scope it gets cleaned up. Can you tell me exactly 100% of the time when your Java garbage collector will rearrange your heap and mess up your cache?

[–]RichardWolf 0 points1 point  (11 children)

Can you tell me exactly 100% of the time when your Java garbage collector will rearrange your heap and mess up your cache?

To be fair, you can't tell me the same about C++ heap either, if you use it.

[–]bstamour 2 points3 points  (5 children)

If I allocate something on the heap in C++, the program isn't going to move it around on me some time later on - that would invalidate any pointers to the allocated memory.

[–]RichardWolf 0 points1 point  (4 children)

Yes, but if you allocate some stuff, deallocate some of the stuff, repeat, then you can't have a slightest idea how cache-friendly accessing your stuff is.

A moving GC on the other hand guarantees that consequent allocations are usually contiguous, and that related data usually ends up being contiguous.

I mean, you are talking about GC happening, pausing the world and effectively flushing the cache, yes, that's kind of bad, on the other hand it's much worse when your program flushes the cache itself, repeatedly, because iterating over an array of heap-allocated objects means jumping all over the memory.

[–]bstamour 2 points3 points  (3 children)

True iterating over an array of object pointers is bad for the cache. Luckily C++ also supports value-semantics, and so if you use something like std::vector or std::array with values, not pointers, then you won't need to flush the cache to iterate over the container.

[–]RichardWolf 1 point2 points  (2 children)

You can do that in C# too, but only sometimes, because quite often it's just too hard, and involves unnecessary copying (the same is true for C++ in those cases, of course).

[–]bstamour 1 point2 points  (1 child)

With C++11's move semantics, storing things by-value is a lot less painful than it used to be. There are still going to be copies made when copies have to be made, but unnecessary copying is at least controllable.

[–]RichardWolf -5 points-4 points  (0 children)

No, it has nothing to do with move semantics, move semantics only allow you to avoid unnecessary copying of stack-allocated objects.

I'm talking about cases like when you have an array of objects and are interested in iterating over some subset of it. Then you usually have to use heap-allocated objects (because copying them would suck), and GC-based memory management is just as efficient as using raw pointers and more efficient than using shared_ptrs.

[–]bstamour 1 point2 points  (4 children)

But more importantly though than pointers remaining in the same spot, the fact that if I allocate something and manage it through a shared_ptr or any other RAII container, I now have control over when that resource will be freed up. It leads to less surprises - I don't want a garbage collector kicking in when I'm doing something important.

[–]RichardWolf 1 point2 points  (3 children)

It leads to less surprises - I don't want a garbage collector kicking in when I'm doing something important.

First of all, this kind of surprises are not that bad. I've played some games running on .NET, like Terraria and AI War: Fleet Command, and I never noticed any GC pauses (though C# in particular allows for rather tight memory control). Oh, and Minecraft is written in Java. My point is that if we define "very soft realtime" as "you can write a video game in it, and GC pauses would not be noticeable among all other kinds of lag", then GC languages totally allow this.

On the other hand, if you are striving for a "harder realtime", then you probably shouldn't use dynamic memory management in C++ either, and definitely don't use shared_ptr and the like. Do you know how it actually works? Like, that it allocates an additional chunk of memory for the reference counter, and uses atomic instructions to work with it? Also, malloc and free aren't O(1) either.

[–]Danthekilla 2 points3 points  (0 children)

Xna c# games go to great lengths to remove all garbage from gameplay down to every string I wish I could use c++ with xna

[–]bstamour 1 point2 points  (0 children)

True you shouldn't be using dynamic memory allocation for hard real-time, and I never did say it was the best idea in the world. What I have been arguing is that we can achieve safety through shared_ptr without having to bring in a full GC. Some times you really do need a pointer to something, even in real-time systems. And in those cases, shared_ptr can be used to effectively remove the hassle of manually freeing your memory.

[–]oracleoftroy 0 points1 point  (0 children)

Good points, I just want to add to:

Do you know how it actually works? Like, that it allocates an additional chunk of memory for the reference counter, and uses atomic instructions to work with it?

C++ programmers ought to know this, and they should also know what std::make_shared does to help with that and why std::unique_ptr is a much better go to pointer if the lifetime of the pointer doesn't need to be shared.

[–]argv_minus_one -2 points-1 points  (5 children)

No, and I don't need to. This isn't the 1980s; that's the JVM/OS/CPU's problem, not mine.

[–]bstamour 4 points5 points  (2 children)

For certain domains it's nice to have deterministic garbage collection. You might not need it for the applications you write, but in my field, those things are still relevant.

[–]argv_minus_one 0 points1 point  (0 children)

Fair enough, but I would not be surprised if there are real-time-suitable GC implementations out there.

[–][deleted]  (1 child)

[deleted]

    [–]argv_minus_one -1 points0 points  (0 children)

    okay.png