www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Do you use D's GC?

reply Kirill <kirill.saidov mail.com> writes:
It's interesting to hear do you use D's GC? Or do you use your 
own custom memory management structure?

How performant is GC?

The reason I'm asking is I'm planning to dive into 3D game dev 
with D as a hobby in an attempt to create a game I dreamed of 
since I was a kid. I'd like to know if GC is worth using at all, 
or should I go with 100% manual memory management.

Any opinion is appreciated. Thanks in advance.
Aug 01
next sibling parent JN <666total wp.pl> writes:
On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?

 How performant is GC?

 The reason I'm asking is I'm planning to dive into 3D game dev 
 with D as a hobby in an attempt to create a game I dreamed of 
 since I was a kid. I'd like to know if GC is worth using at 
 all, or should I go with 100% manual memory management.

 Any opinion is appreciated. Thanks in advance.
I think both approaches are viable. I am making a small 3D game engine in D and I never had many issues with GC performance. In a game, you shouldn't be allocating a lot of stuff on the heap anyway. Most of big objects like buffers, textures should be initialized once during startup anyway. Things like matrices and vectors which you'll be using often are value types so they won't be going through GC anyway. Just avoid things like particle emitter having 10000 particles which are GC-allocated whenever they spawn. Just make an 10000-sized array of particle structs and do the swap-with-last then reduce count by 1 trick. But if you want to go manual memory management, D will allow you to do it.
Aug 01
prev sibling next sibling parent Dukc <ajieskola gmail.com> writes:
On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?
Often. I could avoid it but it's rarely worth it. Well, I do try to avoid heap usage in general when I can easily do so, but I don't often use RAII, let alone `malloc`/`free`. And even when I have done so, it's not so much for performance, it's for portability (through with Dylan Graham's LWDR I'm not sure I have to avoid GC for portability anymore).
 How performant is GC?

 The reason I'm asking is I'm planning to dive into 3D game dev 
 with D as a hobby in an attempt to create a game I dreamed of 
 since I was a kid. I'd like to know if GC is worth using at 
 all, or should I go with 100% manual memory management.

 Any opinion is appreciated. Thanks in advance.
Most people nowadays use an already made game 3D engine - You may well have heard of Unity and Unreal engine. While they do not let a game to be as performant as with a purpose-built engine, the fact that reasonably light 3D games have been made with them for ages speaks a lot. Godot game engine is a great choice IMO, especially with D. It's fully open source, has a good D binding, and it has a better object model than Unity does. Binding here: https://github.com/godot-d/godot-d. And yes, D GC is available with Godot. It's unlikely you'll have problems with it, as the game engine takes care of the heavy crunching - you generally write only the scripts. You may also consider Dagon (https://code.dlang.org/packages/dagon). As a much smaller project it's going to be harder to use it than Godot, but if you want a pure D game engine you might consider it. It's still definitely an easier route than writing your own engine.
Aug 01
prev sibling next sibling parent reply IGotD- <nise nise.com> writes:
On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?

 How performant is GC?

 The reason I'm asking is I'm planning to dive into 3D game dev 
 with D as a hobby in an attempt to create a game I dreamed of 
 since I was a kid. I'd like to know if GC is worth using at 
 all, or should I go with 100% manual memory management.

 Any opinion is appreciated. Thanks in advance.
There is one question I have, let's say you have a big game that uses several gigabytes of RAM. The objects are just allocated once with the GC but once you touch the GC like doing a new (which can be done by a library function), will the GC then start to scan all those gigabytes of data?
Aug 01
next sibling parent Mike Parker <aldacron gmail.com> writes:
On Sunday, 1 August 2021 at 10:36:52 UTC, IGotD- wrote:

 There is one question I have, let's say you have a big game 
 that uses several gigabytes of RAM. The objects are just 
 allocated once with the GC but once you touch the GC like doing 
 a new (which can be done by a library function), will the GC 
 then start to scan all those gigabytes of data?
If it needs to. Not every allocation will trigger a collection. You can play around with something like appending items to an array in a loop and passing `--DRT-gcopt=profile:1` to the program when you run it. This will spit out a report telling you how many collections were run, along with some timing statistics. There's an example here: https://dlang.org/blog/2017/06/16/life-in-the-fast-lane/ It's one of the tools available to make the best use of the GC.
Aug 01
prev sibling parent Adam D Ruppe <destructionator gmail.com> writes:
On Sunday, 1 August 2021 at 10:36:52 UTC, IGotD- wrote:
 will the GC then start to scan all those gigabytes of data?
the GC will only scan blocks that might have pointers in them. so let's say you have objects like class Thing { ubyte[] imageData; this() { imageData = new ubyte[](10_000_000); } } A GC scan of that is actually only like 64 bytes since it knows it doesn't need to look at the image data, only the class and the stack which can actually hold pointers.
Aug 01
prev sibling next sibling parent Mike Parker <aldacron gmail.com> writes:
On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?

 How performant is GC?

 The reason I'm asking is I'm planning to dive into 3D game dev 
 with D as a hobby in an attempt to create a game I dreamed of 
 since I was a kid. I'd like to know if GC is worth using at 
 all, or should I go with 100% manual memory management.

 Any opinion is appreciated. Thanks in advance.
In short, treat GC allocated memory *the same way* you would treat memory allocated and deallocated with malloc and free. For example, in C++ would someone who knows what they're doing allocate memory for large numbers of individual entities, like particles, in inner loops? No. They would preallocate. Do the same in D. The GC isn't going to run a collection behind your back. It's only going to run if you do something that triggers an allocation. ` nogc` on the functions that are called in your inner loops will make sure you don't trigger a collection at the wrong moment. You have other tools if you need them (emphasis on *if you need them*), like pausing the GC, or invoking collection runs manually at specific points. This is the sort of thing you dig into *if* you find the GC is problematic. I'm going to go out on a limb and say the odds are low that the GC will be a problem for you, and lower still if you are smart about using it. There is a class of games and other applications for which GC is certainly going to be problematic no matter how smart the developer is about using it, but I doubt anyone working on a hobby 3D is going to be anywhere near there. Even going full-on GC and being dumb about using it is going to be just fine for many kinds of games. It's all about the scope of the project and your allocations patterns. I mean, you can be less smart about it for games like Pac-Man, Galaga, etc, but you'll need to think about it more for something like Skyrim. Plan your allocation patterns in a way that makes sense for the game you are making. To do that, just follow some simple rules. If it doesn't need to be a class, make it a struct. If it can be allocated on the stack, then don't use `new`. If there's something that needs heap allocation but you can see a way to easily manage it deterministically, then allocate with malloc instead of the GC. Don't do any allocations, including malloc, in your inner loop. Preallocate arrays for things like particles, or use free lists when you need large numbers of GC-managed objects (not good advice for Java anymore, but almost certainly useful in D). And so on. In short, the less pressure you put on the GC, the less impactful its collections. The less often you allocate from the GC, the fewer collections it will run. So use it for the things you need it for, but be strategic about when you call the allocations. This may help you get started: https://dlang.org/blog/the-gc-series/
Aug 01
prev sibling next sibling parent =?UTF-8?B?0JLQuNGC0LDQu9C40Lkg0KTQsNC0?= =?UTF-8?B?0LXQtdCy?= writes:
On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?
 do you use D's GC?
Yes.
 How performant is GC?
It doesn't matter to me. I don't see the difference. While teething an idea, I don't look at performance. Then when the idea is finalized, I improve performance. And here I sometimes prefer nogc nothrow functions. I love D for fast compilation and for the gerbage collector. Without the GC, it would be tedious to programing with keep pointers in mind. For GUI library I prefer nogc + BetterC.
Aug 01
prev sibling next sibling parent Dylan Graham <dylan.graham2000 gmail.com> writes:
On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?
It entirely depends on the scope of the problem. For a script or tool, absolutely yes. Game development? Yes. Embedded? Maybe. I implemented a voxel game (similar to [Blockscape around 2012](https://images.app.goo.gl/7yJAfnUu9wa7A74fA)) and the GC was largely not a problem. The underlying array for a chunk of voxels (chunks come in and out of scope very frequently as the player moves), was `malloc`ed to reduce pressure on the GC (and to enable on-the-fly RLE compression). Otherwise, everything else was GC dependent and I did not have performance problems.
 How performant is GC?
Some people complain about it, but I haven't had an issue. I think my usage of it was before they introduced the parallel-sweep GC. I don't recall GC pauses any longer than 4-5ms, and there was no stutter. D's GC is significantly easier to manage than something like fighting .NET's GC. It always seemed to run, no matter how much I tried to stop allocations (while you can can *temporarily* stop the GC, it wasn't a solution). D's GC only runs *when you allocate with* `new`.
 The reason I'm asking is I'm planning to dive into 3D game dev 
 with D as a hobby in an attempt to create a game I dreamed of 
 since I was a kid. I'd like to know if GC is worth using at 
 all, or should I go with 100% manual memory management.

 Any opinion is appreciated. Thanks in advance.
We might be able to give a more informed answer with some of your planned technical details. As is, I'd advise you use the GC. D is in a very good position to become a gamedev language. The GC is very helpful, but when you really need, it's super easy to opt out. D is about giving *you* power.
Aug 01
prev sibling next sibling parent zjh <fqbqrr 163.com> writes:
On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?
If `D` can provide more infrastructure for `non-GC`, I believe `D` will develop `better and faster`.
Aug 01
prev sibling next sibling parent reply max haughton <maxhaton gmail.com> writes:
On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?

 How performant is GC?

 The reason I'm asking is I'm planning to dive into 3D game dev 
 with D as a hobby in an attempt to create a game I dreamed of 
 since I was a kid. I'd like to know if GC is worth using at 
 all, or should I go with 100% manual memory management.

 Any opinion is appreciated. Thanks in advance.
I use the GC. The GC is an extremely powerful tool for productivity. For a game your issue will be non-deterministic latency i.e. GC pauses. For this, I would recommend having a strategy for avoiding the GC - other people will write here and have written extensively before on how to do this, so I won't repeat all of those points and points to be. It may be worth a warning here: If you are going into a new field, you probably want to learn that field *then* try and do that field well rather than trying to learn how to make a good game engine and any game engine at the same time. A small tip for any memory allocation: Before being clever and thinking about the internals of your memory allocator (which is important, to be clear), try to allocate less memory first - sounds simple but memory you never allocate has a cost of exactly zero. Enjoy.
Aug 01
parent reply evilrat <evilrat666 gmail.com> writes:
On Sunday, 1 August 2021 at 14:02:46 UTC, max haughton wrote:
 On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?

 How performant is GC?

 The reason I'm asking is I'm planning to dive into 3D game dev 
 with D as a hobby in an attempt to create a game I dreamed of 
 since I was a kid. I'd like to know if GC is worth using at 
 all, or should I go with 100% manual memory management.

 Any opinion is appreciated. Thanks in advance.
I use the GC. The GC is an extremely powerful tool for productivity. For a game your issue will be non-deterministic latency i.e. GC pauses.
Just to add, from my rough tests it shows that you can have unnoticeable collections for up to 300MB heap size depending on CPU/RAM specs, after that there is clearly perceivable stutter that drags FPS down esp. with loop allocations. What this means in practice - it should be possible to go full OOP crap for game simulation using lightweight classes without any hiccups even with GC enabled, but all asset data should be handled differently and taken out of GC scannable heap to avoid long pauses. But in reality one would probably choose another allocation strategy that will probably accounts for disabling GC until certain point later in time when collection pauses won't matter and do manual collect there (on pause menu, respawn, level change, etc...)
Aug 01
next sibling parent russhy <russhy gmail.com> writes:
I only use GC for process that doesn't need to be realtime

For anything else (including my game engine) i don't use GC at 
all, instead i use allocators (malloc/free most of the time)

If you plan to make a game, try to avoid the GC as much as 
possible, it's not incremental, so whever it needs to do a 
collection, it'll pause all the threads, depending on the 
structure of the heap memory it can take multiple frames


But that's also a valid concern if you misuse malloc/free, so 
it's not an issue with the GC

But with games, you want to make sure you control the memory 
allocation strategy, and GC doesn't help with that

You can always GC.disable() and call GC.collect() during loading 
screens, but again, control your allocation strategy!
Aug 01
prev sibling next sibling parent reply russhy <russhy gmail.com> writes:
 Just to add, from my rough tests it shows that you can have 
 unnoticeable collections for up to 300MB heap size depending on 
 CPU/RAM specs, after that there is clearly perceivable stutter 
 that drags FPS down esp. with loop allocations.
16ms per frame at 60FPS, anything above will introduce frame stutters Even if it's one every minutes, user will notice, games need predictable performance, you don't want to miss a combo because your GC decided to collect this frame for up to 3 frames GC is not an issue if you manually manage it GC.disable() then GC.collect() during loading screen But if your game never has loading screens, or if they are spaced out for way too long, then it's preferable to manage everything without it at all Pool entities, use arena allocators, GC only introduce issues that you have to workaround (threading for ex)
Aug 01
parent russhy <russhy gmail.com> writes:
Generally GC is not an issue, until it becomes an issue

Use it with caution or manage things by yourself

The most important thing to do is to know exactly what you need, 
and when

Avoid heap allocation during hot loops at all cost, no matter if 
it's GC or malloc, they both slow

Remember frame budget is only 16ms per frame for 60FPS, stutters 
are not an option if you want a smooth user experience

And if people use 120HZ monitors, or 144HZ, then the frame budget 
becomes even lower

GC is faster at allocating memory, but collections induces pauses


As other said D is great at providing tools to avoid GC, so use 
that at your benefit

And as i said in other posts above, control your memory 
allocation strategy from the start, and things will be easier to 
manage
Aug 01
prev sibling parent reply IGotD- <nise nise.com> writes:
On Sunday, 1 August 2021 at 14:43:47 UTC, evilrat wrote:
 What this means in practice - it should be possible to go full 
 OOP crap for game simulation using lightweight classes without 
 any hiccups even with GC enabled, but all asset data should be 
 handled differently and taken out of GC scannable heap to avoid 
 long pauses.
I'm kind of skeptical towards tracing GC for games. Think of thousands of objects, usually of the same type. These objects are often full of references to other objects and they often points to each other as there might be some relation. This is a lot of memory, that is also scattered around in the memory. Scanning these will take time. For this type of objects I would go for a pool that is outside GC. Also how the reference each other could be solved by reference counting in order to minimize memory leaks. Other suggestions is that object references each other using a hash table. This rolling identifier/hash lookup is often used in operating systems (file handles for example) as pointers cannot be used in order to distinguish a resource. Often memory management in games kind of falls outside the convenience of GC as the demand is so special, not only because of performance but also when it comes to data structures.
Aug 02
next sibling parent evilrat <evilrat666 gmail.com> writes:
On Monday, 2 August 2021 at 15:43:24 UTC, IGotD- wrote:
 On Sunday, 1 August 2021 at 14:43:47 UTC, evilrat wrote:
 What this means in practice - it should be possible to go full 
 OOP crap for game simulation using lightweight classes without 
 any hiccups even with GC enabled, but all asset data should be 
 handled differently and taken out of GC scannable heap to 
 avoid long pauses.
I'm kind of skeptical towards tracing GC for games. Think of thousands of objects, usually of the same type. These objects are often full of references to other objects and they often points to each other as there might be some relation. This is a lot of memory, that is also scattered around in the memory. Scanning these will take time. For this type of objects I would go for a pool that is outside GC. Also how the reference each other could be solved by reference counting in order to minimize memory leaks. Other suggestions is that object references each other using a hash table. This rolling identifier/hash lookup is often used in operating systems (file handles for example) as pointers cannot be used in order to distinguish a resource. Often memory management in games kind of falls outside the convenience of GC as the demand is so special, not only because of performance but also when it comes to data structures.
Of course, that's why I mentioned that, even if GC performance is OK it is still better to design with what you've said in mind.
Aug 02
prev sibling next sibling parent reply Paulo Pnito <pjmlp progtools.org> writes:
On Monday, 2 August 2021 at 15:43:24 UTC, IGotD- wrote:
 On Sunday, 1 August 2021 at 14:43:47 UTC, evilrat wrote:
 What this means in practice - it should be possible to go full 
 OOP crap for game simulation using lightweight classes without 
 any hiccups even with GC enabled, but all asset data should be 
 handled differently and taken out of GC scannable heap to 
 avoid long pauses.
I'm kind of skeptical towards tracing GC for games. Think of thousands of objects, usually of the same type. These objects are often full of references to other objects and they often points to each other as there might be some relation. This is a lot of memory, that is also scattered around in the memory. Scanning these will take time. For this type of objects I would go for a pool that is outside GC. Also how the reference each other could be solved by reference counting in order to minimize memory leaks. Other suggestions is that object references each other using a hash table. This rolling identifier/hash lookup is often used in operating systems (file handles for example) as pointers cannot be used in order to distinguish a resource. Often memory management in games kind of falls outside the convenience of GC as the demand is so special, not only because of performance but also when it comes to data structures.
It is more than enough for Flash like games, honestly plenty of indies will never make it beyond that, so why bother for the ultimate weapon if they they on the first day on the battlefield? Don't dismiss languages on how well they can achieve Fortnight, when not even able to beat Stardew Valley or Bastion sales.
Aug 02
parent IGotD- <nise nise.com> writes:
On Monday, 2 August 2021 at 18:10:03 UTC, Paulo Pnito wrote:
 It is more than enough for Flash like games, honestly plenty of 
 indies will never make it beyond that, so why bother for the 
 ultimate weapon if they they on the first day on the 
 battlefield?

 Don't dismiss languages on how well they can achieve Fortnight, 
 when not even able to beat Stardew Valley or Bastion sales.
Depends on what you are aiming for, for smaller games GC is probably enough. Let's not forget this interesting D conf seminar. https://www.youtube.com/watch?v=7YjLW7anNfc Where the solution was to disable the GC collecting. For people who haven't seen it this could be interesting as it is the only what I know of example where D is used in a high budget game.
Aug 02
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Aug 02, 2021 at 03:43:24PM +0000, IGotD- via Digitalmars-d wrote:
[...]
 I'm kind of skeptical towards tracing GC for games. Think of thousands
 of objects, usually of the same type. These objects are often full of
 references to other objects and they often points to each other as
 there might be some relation.
[...] I don't have that much experience with game programming, but have experimented with things like ECS, which kinda solves this problem at least partially, by keeping everything in arrays. References between objects are represented by entity IDs rather than straight pointers, and arrays can be allocated in large blocks at a time instead of one allocation per object, so there's much less GC pressure. ECS is also more conducive to representing in-game objects than OO-style objects IMO, especially in games where objects can undergo extensive changes that aren't easily mapped to the OO paradigm. Of course, an ECS implementation could also just manage its own memory instead of relying on GC. In any case, high performance + frequent allocation of small objects == trouble (even if you manually manage memory with malloc/free). If you find yourself in that situation, you inevitably have to address a lot of the same kind of issues that ECS addresses anyway. So this problem isn't necessarily GC-specific (though it tends to become more evident in GC environments), but a more general problem of memory management and object representation in games. T -- MASM = Mana Ada Sistem, Man!
Aug 02
prev sibling next sibling parent reply Guillaume Piolat <first.last gmail.com> writes:
On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?

 How performant is GC?

 The reason I'm asking is I'm planning to dive into 3D game dev 
 with D as a hobby in an attempt to create a game I dreamed of 
 since I was a kid. I'd like to know if GC is worth using at 
 all, or should I go with 100% manual memory management.

 Any opinion is appreciated. Thanks in advance.
For Vibrant which is a very simple game (https://store.steampowered.com/app/712430/Vibrant/) I did get some GC pauses so the mitigation I used in the end was: - memory pools - deregistering audio thread, using core.atomic for game => audio communication - minimize GC heap size. In particular, a GC void[] will be scanned but an ubyte[] won't IIRC. All in all any time spent with GC optimization is well compensated by all the time the GC (and D) gives you in tooling, and non-realtime stuff. Don't go with 100% manual memory management if you can avoid it! But you can go deterministic destruction with https://dlang.org/library/core/memory/gc.in_finalizer.html
Aug 02
parent reply Guillaume Piolat <first.last gmail.com> writes:
On Monday, 2 August 2021 at 08:25:28 UTC, Guillaume Piolat wrote:
 On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:

 I did get some GC pauses
GC performance has been much improved since. It would be great to have new guidelines about "how much GC heap will scan in <1ms" because at one point the research by Infognition said it was only 100kb. http://www.infognition.com/blog/2014/the_real_problem_with_gc_in_d.html
Aug 02
parent reply Joakim =?UTF-8?B?QnLDpG5uc3Ryw7Zt?= <notfornow dev.null.com> writes:
On Monday, 2 August 2021 at 08:27:51 UTC, Guillaume Piolat wrote:
 On Monday, 2 August 2021 at 08:25:28 UTC, Guillaume Piolat 
 wrote:
 On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:

 I did get some GC pauses
GC performance has been much improved since. It would be great to have new guidelines about "how much GC heap will scan in <1ms" because at one point the research by Infognition said it was only 100kb. http://www.infognition.com/blog/2014/the_real_problem_with_gc_in_d.html
The fork based GC is merged https://github.com/dlang/druntime/pull/3514 :) It would be interesting to read an article about it. Maybe it improves the use case discussed in this thread? // Joakim
Aug 02
parent reply evilrat <evilrat666 gmail.com> writes:
On Monday, 2 August 2021 at 08:49:36 UTC, Joakim Brännström wrote:
 The fork based GC is merged 
 https://github.com/dlang/druntime/pull/3514 :)
 It would be interesting to read an article about it.
 Maybe it improves the use case discussed in this thread?
In gamedev context probably not, unless there is already some fork mechanism on Windows that i'm not aware of.
Aug 02
parent rikki cattermole <rikki cattermole.co.nz> writes:
On 02/08/2021 9:32 PM, evilrat wrote:
 unless there is already some fork mechanism on Windows that i'm not 
 aware of.
There is snapshoting which is essentially a fork without any threads that you can introspect from your host process.
Aug 02
prev sibling next sibling parent JN <666total wp.pl> writes:
On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?

 How performant is GC?

 The reason I'm asking is I'm planning to dive into 3D game dev 
 with D as a hobby in an attempt to create a game I dreamed of 
 since I was a kid. I'd like to know if GC is worth using at 
 all, or should I go with 100% manual memory management.

 Any opinion is appreciated. Thanks in advance.
Here's a counterpoint article about D's GC being a nuisance in the context of game development: https://www.benjamin-thaut.de/archives/20 be aware though the article is from 2012, so there may have been many improvements to the GC since that time.
Aug 02
prev sibling next sibling parent reply workman <workman gmail.com> writes:
On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?

 How performant is GC?

 The reason I'm asking is I'm planning to dive into 3D game dev 
 with D as a hobby in an attempt to create a game I dreamed of 
 since I was a kid. I'd like to know if GC is worth using at 
 all, or should I go with 100% manual memory management.

 Any opinion is appreciated. Thanks in advance.
The D language claim support NOGC Programming, but there is no ecosystem for this. It force people to use GC if they want use library. D GC is not good as any other popular language. You will find there is a lot library author abandoned they projects in last decade, people just leave after invest a lot time and resource.
Aug 02
next sibling parent Mike Parker <aldacron gmail.com> writes:
On Tuesday, 3 August 2021 at 05:36:12 UTC, workman wrote:

 The D language claim support NOGC Programming, but there is no 
 ecosystem for this. It force people to use GC if they want use 
 library.
That's just not true. The language does not *force* you to use the GC. But it *is* a language that was designed with the GC in mind, so if you want to cut it out completely then you are going to have to do some things yourself that you otherwise wouldn't have to. It's all about tradeoffs. But that's entirely your choice, just as it is for library authors who can choose to use the GC or not. The language does it force it either way.
Aug 02
prev sibling parent reply russhy <russhy gmail.com> writes:
On Tuesday, 3 August 2021 at 05:36:12 UTC, workman wrote:
 On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?

 How performant is GC?

 The reason I'm asking is I'm planning to dive into 3D game dev 
 with D as a hobby in an attempt to create a game I dreamed of 
 since I was a kid. I'd like to know if GC is worth using at 
 all, or should I go with 100% manual memory management.

 Any opinion is appreciated. Thanks in advance.
The D language claim support NOGC Programming, but there is no ecosystem for this. It force people to use GC if they want use library. D GC is not good as any other popular language. You will find there is a lot library author abandoned they projects in last decade, people just leave after invest a lot time and resource.
WHY DO YOU LIE?! there is a strong ecosystem for system libraries and nogc libraries in D and you can plug in what ever C libraries you want, so you already can consume the WHOLE C ecosystem, out of the box saying there is no ecosystem is plain and simple dishonest and a PURE LIE
Aug 03
parent reply workman <workman gmail.com> writes:
On Tuesday, 3 August 2021 at 12:26:14 UTC, russhy wrote:
 WHY DO YOU LIE?!

 there is a strong ecosystem for system libraries and nogc 
 libraries in D

 and you can plug in what ever C libraries you want, so you 
 already can consume the WHOLE C ecosystem, out of the box

 saying there is no ecosystem is plain and simple dishonest and 
 a PURE LIE
I am sorry if I use the wrong words that hurt you feeling, but that is just my opinion.
Aug 03
parent russhy <russhy gmail.com> writes:
On Tuesday, 3 August 2021 at 15:28:57 UTC, workman wrote:
 On Tuesday, 3 August 2021 at 12:26:14 UTC, russhy wrote:
 WHY DO YOU LIE?!

 there is a strong ecosystem for system libraries and nogc 
 libraries in D

 and you can plug in what ever C libraries you want, so you 
 already can consume the WHOLE C ecosystem, out of the box

 saying there is no ecosystem is plain and simple dishonest and 
 a PURE LIE
I am sorry if I use the wrong words that hurt you feeling, but that is just my opinion.
Don't make it personal, i talk about the lies you spread, it has nothing to do with feelings
Aug 03
prev sibling next sibling parent reply Gregor =?UTF-8?B?TcO8Y2ts?= <gregormueckl gmx.de> writes:
On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?

 How performant is GC?

 The reason I'm asking is I'm planning to dive into 3D game dev 
 with D as a hobby in an attempt to create a game I dreamed of 
 since I was a kid. I'd like to know if GC is worth using at 
 all, or should I go with 100% manual memory management.

 Any opinion is appreciated. Thanks in advance.
The D garbage collector seems reasonable for applications with small (object sized) allocations. But that changes when you allocate large blocks of memory: due to a bug internal to the tracking of allocated pages, performance gradually degrades over time. So if you have to allocate large(ish) buffers regularly, it'll show over time. I reported that bug here with a repro case, but it didn't get any attention yet: https://issues.dlang.org/show_bug.cgi?id=20434 I haven't managed to understand thag part of the GC enough to submit a patch myself :(.
Aug 03
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/3/21 5:15 AM, Gregor Mückl wrote:
 On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your own 
 custom memory management structure?

 How performant is GC?

 The reason I'm asking is I'm planning to dive into 3D game dev with D 
 as a hobby in an attempt to create a game I dreamed of since I was a 
 kid. I'd like to know if GC is worth using at all, or should I go with 
 100% manual memory management.

 Any opinion is appreciated. Thanks in advance.
The D garbage collector seems reasonable for applications with small (object sized) allocations. But that changes when you allocate large blocks of memory: due to a bug internal to the tracking of allocated pages, performance gradually degrades over time. So if you have to allocate large(ish) buffers regularly, it'll show over time. I reported that bug here with a repro case, but it didn't get any attention yet: https://issues.dlang.org/show_bug.cgi?id=20434 I haven't managed to understand thag part of the GC enough to submit a patch myself :(.
Is that repro case doing what you think it is doing? It appears to keep adding more and more larger allocations to the mix. It seems you are calculating a `size` variable and never using it. I think possibly you meant to use `size * 1024 * 1024` instead of `i * 1024 * 1024`. In regards to the conservative nature of the GC, the larger the blocks get, the more chances they get "accidentally" pointed at by the stack (or some other culprit). 64-bit memory space should alleviate a lot of this, but I think there are still cases where it can pin data unintentionally. -Steve
Aug 03
next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/3/21 7:34 AM, Steven Schveighoffer wrote:

 Is that repro case doing what you think it is doing? It appears to keep 
 adding more and more larger allocations to the mix.
You didn't reply in the bug thread. ;) Ali
Aug 03
prev sibling parent reply Gregor =?UTF-8?B?TcO8Y2ts?= <gregormueckl gmx.de> writes:
On Tuesday, 3 August 2021 at 14:34:19 UTC, Steven Schveighoffer 
wrote:
 On 8/3/21 5:15 AM, Gregor Mückl wrote:
 The D garbage collector seems reasonable for applications with 
 small (object sized) allocations. But that changes when you 
 allocate large blocks of memory: due to a bug internal to the 
 tracking of allocated pages, performance gradually degrades 
 over time. So if you have to allocate large(ish) buffers 
 regularly, it'll show over time. I reported that bug here with 
 a repro case, but it didn't get any attention yet:
 
 https://issues.dlang.org/show_bug.cgi?id=20434
 
 I haven't managed to understand thag part of the GC enough to 
 submit a patch myself :(.
Is that repro case doing what you think it is doing? It appears to keep adding more and more larger allocations to the mix. It seems you are calculating a `size` variable and never using it. I think possibly you meant to use `size * 1024 * 1024` instead of `i * 1024 * 1024`. In regards to the conservative nature of the GC, the larger the blocks get, the more chances they get "accidentally" pointed at by the stack (or some other culprit). 64-bit memory space should alleviate a lot of this, but I think there are still cases where it can pin data unintentionally. -Steve
I apologize for not replying earlier. I was very busy with real life stuff since I posted this. Also, I feel REALLY embarrassed. You are right. I am sorry for wasting time with this. I was 100% certain that my code was right when I opened the bug report and I am sure that I checked it multiple times. But going back to the example program I have locally, it clearly contains this stupid bug. I fixed the allocation size as you said and now I can't reproduce the behavior I remember. I've checked several dmd builds between 2.088 and 2.096 again and it doesn't show. So the GC is just fine after all - and I've made an idiot of myself. Again.
Aug 14
parent Steven Schveighoffer <schveiguy gmail.com> writes:
Don't feel bad, we've ALL done something like this!

Cheers!

-Steve
Aug 14
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sun, Aug 01, 2021 at 08:54:05AM +0000, Kirill via Digitalmars-d wrote:
 It's interesting to hear do you use D's GC? Or do you use your own
 custom memory management structure?
 
 How performant is GC?
 
 The reason I'm asking is I'm planning to dive into 3D game dev with D
 as a hobby in an attempt to create a game I dreamed of since I was a
 kid. I'd like to know if GC is worth using at all, or should I go with
 100% manual memory management.
[...] My approach to D's GC is: (1) Use it by default until it starts showing up as a bottleneck in your profiler. (2) When it does show up as a bottleneck, the fix is often simple and yields good benefits. E.g., in one of my projects, after the GC showed up as a bottleneck, I quickly pinpointed the problem to a function in an inner loop that was allocating a new array every iteration. Fixing that to reuse a previously-allocated array (maybe about 5 lines' change) immediately gave me 20-30% performance boost. There were a couple of other similar small code changes to reduce GC pressure, and replace some small bits of GC code in inner loops where performance matters the most. (3) If performance is still not good enough, there are other ways of controlling the GC. In the aforementioned project, for example, after the array optimization I found that GC collections were taking place too often. So I added GC.stop to the start of my program, and scheduled my own calls to GC.collect at a lower frequency, and got about another 20-30% performance improvement. Overall, I think I got about 50-60% performance improvement just by several small code changes to an essentially GC-centric codebase. By writing GC code I saved countless days of writing code for manually managing memory (and weeks of pulling out my hair to debug said code). Only in actual hotspots where the GC becomes a hindrance, I spent some focused effort to either optimize GC usage, or replace small parts of the code (in inner loops and other bottlenecks) with manually-managed memory. Much faster development time than if I had written *everything* to be nogc. Most of that effort would have been wasted on code that doesn't even lie in the bottleneck and therefore doesn't actually matter to performance. tl;dr: don't fear the GC, just use it freely until your profiler has actually identified the GC as the bottleneck. Then strategically optimize those hotspots, optionally replace them with nogc code, etc., with much less effort than writing your entire application with nogc. T -- "Hi." "'Lo."
Aug 03
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/3/21 9:31 AM, H. S. Teoh wrote:

 (1) Use it by default until it starts showing up as a bottleneck in your
 profiler.

 (2) When it does show up as a bottleneck, [...]
That's engineering! :) However, dmd's -profile=gc switch seems to have a bug reported by multiple people where one may get a segmentation fault (or was it -profile?). Even though I've seen it as well, it is not clear whether it's my own code causing errors in a destructor.
 Overall, I think I got about 50-60% performance improvement just by
 several small code changes to an essentially GC-centric codebase.
Same here. One surprising pessimization which I have not mentioned publicly before was with assigning to the .length property of a buffer. Was it supposed to allocate? I had the following function: void ensureHasRoom(ref ubyte[] buffer, size_t length) { buffer.length = length; } My idea was I would blindly assign and even if the length was reduced, the *capacity* would not change and memory would *not* be allocated by a later assignment. Unfortunately, that function was causing GC allocations at least with 2.084.1 perhaps in the presence of other slices to the same elements in my program. Changing it to the following more sensible approach reduced the allocations a lot: void ensureHasRoom(ref ubyte[] buffer, size_t length) { if (buffer.length < length) { buffer.length = length; } } I can't be sure now whether it was related to the presence of other slices. Possible... Anyway, that quick fix was a huge improvement. Ali
Aug 03
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/3/21 1:53 PM, Ali Çehreli wrote:
 On 8/3/21 9:31 AM, H. S. Teoh wrote:
 
  > (1) Use it by default until it starts showing up as a bottleneck in your
  > profiler.
  >
  > (2) When it does show up as a bottleneck, [...]
 
 That's engineering! :)
 
 However, dmd's -profile=gc switch seems to have a bug reported by 
 multiple people where one may get a segmentation fault (or was it 
 -profile?). Even though I've seen it as well, it is not clear whether 
 it's my own code causing errors in a destructor.
 
  > Overall, I think I got about 50-60% performance improvement just by
  > several small code changes to an essentially GC-centric codebase.
 
 Same here.
 
 One surprising pessimization which I have not mentioned publicly before 
 was with assigning to the .length property of a buffer. Was it supposed 
 to allocate? I had the following function:
 
 void ensureHasRoom(ref ubyte[] buffer, size_t length) {
    buffer.length = length;
 }
 
 My idea was I would blindly assign and even if the length was reduced, 
 the *capacity* would not change and memory would *not* be allocated by a 
 later assignment.
Let's rewrite this into appending to see why this doesn't work: ```d buffer = new int[100]; // start with some data; auto buffer2 = buffer; // keep a reference to it (to give us a reason to keep the data) buffer = buffer[0 .. 50]; // "shrink" the length buffer ~= 10; // appending, will reallocate because otherwise we stomp on buffer2 ``` It's no different for length setting: ```d buffer = new int[100]; auto buffer2 = buffer; buffer.length = 50; buffer.length = 51; // must reallocate buffer[$-1] = 10; ``` In order for a length change to *not* reallocate, you have to call `assumeSafeAppend` on that adjusted buffer, to let the runtime know that we don't care about any existing data that might be referenced by others. -Steve
Aug 03
next sibling parent reply jfondren <julian.fondren gmail.com> writes:
On Tuesday, 3 August 2021 at 18:18:48 UTC, Steven Schveighoffer 
wrote:
 It's no different for length setting:

 ```d
 buffer = new int[100];
 auto buffer2 = buffer;
 buffer.length = 50;
 buffer.length = 51; // must reallocate
 buffer[$-1] = 10;
 ```
All of the buffer-stomping "must reallocate" cases are preserved in the rewrite that only assigns buffer.length when the new value is larger. The cases that were omitted, that were a performance drain, were same-length or less-length assignments.
Aug 03
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/3/21 2:21 PM, jfondren wrote:
 On Tuesday, 3 August 2021 at 18:18:48 UTC, Steven Schveighoffer wrote:
 It's no different for length setting:

 ```d
 buffer = new int[100];
 auto buffer2 = buffer;
 buffer.length = 50;
 buffer.length = 51; // must reallocate
 buffer[$-1] = 10;
 ```
All of the buffer-stomping "must reallocate" cases are preserved in the rewrite that only assigns buffer.length when the new value is larger. The cases that were omitted, that were a performance drain, were same-length or less-length assignments.
There is not a reallocation on shrinking of length. Or am I misunderstanding your statement? -Steve
Aug 03
parent reply jfondren <julian.fondren gmail.com> writes:
On Tuesday, 3 August 2021 at 18:34:55 UTC, Steven Schveighoffer 
wrote:
 On 8/3/21 2:21 PM, jfondren wrote:
 On Tuesday, 3 August 2021 at 18:18:48 UTC, Steven 
 Schveighoffer wrote:
 It's no different for length setting:

 ```d
 buffer = new int[100];
 auto buffer2 = buffer;
 buffer.length = 50;
 buffer.length = 51; // must reallocate
 buffer[$-1] = 10;
 ```
All of the buffer-stomping "must reallocate" cases are preserved in the rewrite that only assigns buffer.length when the new value is larger. The cases that were omitted, that were a performance drain, were same-length or less-length assignments.
There is not a reallocation on shrinking of length. Or am I misunderstanding your statement?
I think you're understanding it but not believing it. Again: ```d void ensureHasRoom(ref ubyte[] buffer, size_t length) { buffer.length = length; // this is a serious bottleneck } void ensureHasRoom(ref ubyte[] buffer, size_t length) { if (buffer.length < length) { buffer.length = length; // this is fine actually } } ``` The story is that the situation was improved by excluding only those cases that should not have incurred any reallocations. Every single invocation of the bottlenecking `ensureHasRoom` that should have reallocated would still do so with the fixed `ensureHasRoom`. So something else was going on.
Aug 03
next sibling parent reply jfondren <julian.fondren gmail.com> writes:
On Tuesday, 3 August 2021 at 19:04:06 UTC, jfondren wrote:
 ```d
 void ensureHasRoom(ref ubyte[] buffer, size_t length) {
   buffer.length = length; // this is a serious bottleneck
 }

 void ensureHasRoom(ref ubyte[] buffer, size_t length) {
   if (buffer.length < length) {
     buffer.length = length; // this is fine actually
   }
 }
 ```

 The story is that the situation was improved by excluding only 
 those cases that should not have incurred any reallocations. 
 Every single invocation of the bottlenecking `ensureHasRoom` 
 that should have reallocated would still do so with the fixed 
 `ensureHasRoom`. So something else was going on.
ah. No, I get it: this was probably shrinking and then regrowing buffer.length across separate calls, which would incur reallocations on the regrowth.
Aug 03
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/3/21 3:16 PM, jfondren wrote:
 On Tuesday, 3 August 2021 at 19:04:06 UTC, jfondren wrote:
 ```d
 void ensureHasRoom(ref ubyte[] buffer, size_t length) {
   buffer.length = length; // this is a serious bottleneck
 }

 void ensureHasRoom(ref ubyte[] buffer, size_t length) {
   if (buffer.length < length) {
     buffer.length = length; // this is fine actually
   }
 }
 ```

 The story is that the situation was improved by excluding only those 
 cases that should not have incurred any reallocations. Every single 
 invocation of the bottlenecking `ensureHasRoom` that should have 
 reallocated would still do so with the fixed `ensureHasRoom`. So 
 something else was going on.
ah. No, I get it: this was probably shrinking and then regrowing buffer.length across separate calls, which would incur reallocations on the regrowth.
Yep, correct! Sorry I didn't see this before I did the other reply. -Steve
Aug 03
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/3/21 3:04 PM, jfondren wrote:
 On Tuesday, 3 August 2021 at 18:34:55 UTC, Steven Schveighoffer wrote:
 On 8/3/21 2:21 PM, jfondren wrote:
 On Tuesday, 3 August 2021 at 18:18:48 UTC, Steven Schveighoffer wrote:
 It's no different for length setting:

 ```d
 buffer = new int[100];
 auto buffer2 = buffer;
 buffer.length = 50;
 buffer.length = 51; // must reallocate
 buffer[$-1] = 10;
 ```
All of the buffer-stomping "must reallocate" cases are preserved in the rewrite that only assigns buffer.length when the new value is larger. The cases that were omitted, that were a performance drain, were same-length or less-length assignments.
There is not a reallocation on shrinking of length. Or am I misunderstanding your statement?
I think you're understanding it but not believing it. Again: ```d void ensureHasRoom(ref ubyte[] buffer, size_t length) {   buffer.length = length; // this is a serious bottleneck } void ensureHasRoom(ref ubyte[] buffer, size_t length) {   if (buffer.length < length) {     buffer.length = length; // this is fine actually   } } ``` The story is that the situation was improved by excluding only those cases that should not have incurred any reallocations. Every single invocation of the bottlenecking `ensureHasRoom` that should have reallocated would still do so with the fixed `ensureHasRoom`. So something else was going on.
The allocation doesn't happen on the shrinking, it happens on the regrowing. So e.g. you have: ```d int[] buf; ensureHasRoom(buf, 10); // allocates buf[0 .. 10] = 42; ensureHasRoom(buf, 5); // does not reallocate in both versions buf[0 .. 5] = 43; ensureHasRoom(buf, 10); // Maybe reallocates (see below) buf[0 .. 10] = 44; ``` So before Ali made the change, the line to regrow to 10 elements DID reallocate, because now it might stomp on data held elsewhere (the runtime has no way of knowing how many references to the array buffer there are, it just knows how much has been used). After the change, the shrinking to 5 did not actually set the length to 5, the function left it at 10, so the "regrowing" sets the length from 10 to 10. This means no reallocation on the *subsequent* length change. The serious bottleneck is on the growing (unnecessarily), not in the shrinking. Clearly, the code in question can handle a buffer that isn't the exact length, but has at least enough length. Here's how I would write the function (if the buffer had to be the exact length needed): ```d void ensureHasRoom(ref ubyte[] buffer, size_t length) { bool shouldAssume = buffer.length > length; buffer.length = length; if(shouldAssume) buffer.assumeSafeAppend; } ``` which would have the same effect (though be slightly less efficient since it would still have to be an opaque call into the runtime, and possibly have to fetch block metadata). -Steve
Aug 03
parent jfondren <julian.fondren gmail.com> writes:
On Tuesday, 3 August 2021 at 19:19:46 UTC, Steven Schveighoffer 
wrote:
 The allocation doesn't happen on the shrinking, it happens on 
 the regrowing.
Aye, I had some kind of sleep deprivation mental block on this function getting called repeatedly for the same buffer with different lengths. Imagine, instead, 10k separate buffers and a _single_ call of this function on each with a random length. In this case the reallocating calls would be the same with/without the fix.
Aug 03
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/3/21 11:18 AM, Steven Schveighoffer wrote:

 In order for a length change to *not* reallocate, you have to call
 `assumeSafeAppend` on that adjusted buffer, to let the runtime know that
 we don't care about any existing data that might be referenced by others.
Makes sense. Yes, I use assumeSafeAppend mostly on function-local-static buffers. (Similarly, Appender.clear() for appenders.) Ali
Aug 03
prev sibling next sibling parent John Colvin <john.loughran.colvin gmail.com> writes:
On Sunday, 1 August 2021 at 08:54:05 UTC, Kirill wrote:
 It's interesting to hear do you use D's GC? Or do you use your 
 own custom memory management structure?

 How performant is GC?

 The reason I'm asking is I'm planning to dive into 3D game dev 
 with D as a hobby in an attempt to create a game I dreamed of 
 since I was a kid. I'd like to know if GC is worth using at 
 all, or should I go with 100% manual memory management.

 Any opinion is appreciated. Thanks in advance.
I think GC fear is massively overblown, but I would be quite careful about using it heavily in a 3D game. Unpredictable pauses are your enemy. So using it to load/build e.g. level assets would be fine, but allocating anything short-lived? No way. I would likely make the core game loop nogc or be very strategic in allowing it to run. Then again, I have never build a 3d game before, only 3d scientific animations, so my advice is coming from a relatively weak position: I know D very well and have heard how games work.
Aug 03
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
There's some good replies here.

When I write high performance code, I use a mix of manual and GC allocation. 
Stuff that's critical for performance or recycling memory, I use manual. For
not 
critical stuff, like setup and configuration code, I use the GC because it's so 
much more convenient.
Aug 03
parent reply Walter Bright <newshound2 digitalmars.com> writes:
BTW, regardless of what language you use, or use GC or not, there's no way to 
write a high performance program without being cognizant of its memory 
consumption patterns.
Aug 03
parent reply Brian Tiffin <btiffin gnu.org> writes:
On Tuesday, 3 August 2021 at 19:33:27 UTC, Walter Bright wrote:
 BTW, regardless of what language you use, or use GC or not, 
 there's no way to write a high performance program without 
 being cognizant of its memory consumption patterns.
Hear, hear. There have been others, but this one hit me like lightning. I'm now talking to you, and about you to everyone else, Walter. :) I'm still fairly new here. Does anyone have a Walter's Wisdoms file? Add this one. An ageless wisdom, well spoken.
Aug 04
next sibling parent Guillaume Piolat <first.last gmail.com> writes:
On Wednesday, 4 August 2021 at 21:58:58 UTC, Brian Tiffin wrote:
 I'm still fairly new here.  Does anyone have a Walter's Wisdoms 
 file?  Add this one.  An ageless wisdom, well spoken.
On bugs vs input errors: "I believe this is a misunderstanding of what exceptions are for. "File not found" exceptions, and other errors detected in inputs, are routine and routinely recoverable. This discussion has come up repeatedly in the last 30 years. It's root is always the same - conflating handling of input errors, and handling of bugs in the logic of the program. The two are COMPLETELY different and dealing with them follow completely different philosophies, goals, and strategies. Input errors are not bugs, and vice versa. There is no overlap." - Walter Bright, 2014 Programming Languages on Crack: https://forum.dlang.org/post/saeagb$10t6$1 digitalmars.com AST macros: https://forum.dlang.org/post/qkpgea$1am3$1 digitalmars.com https://forum.dlang.org/post/l6co6u$vo$1 digitalmars.com Andrei also have "Great work is the cure for Good work" https://forum.dlang.org/post/q7u6g1$94p$1 digitalmars.com
Aug 04
prev sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Aug 04, 2021 at 09:58:58PM +0000, Brian Tiffin via Digitalmars-d wrote:
 On Tuesday, 3 August 2021 at 19:33:27 UTC, Walter Bright wrote:
 BTW, regardless of what language you use, or use GC or not, there's
 no way to write a high performance program without being cognizant
 of its memory consumption patterns.
Hear, hear. There have been others, but this one hit me like lightning. I'm now talking to you, and about you to everyone else, Walter. :) I'm still fairly new here. Does anyone have a Walter's Wisdoms file? Add this one. An ageless wisdom, well spoken.
Here the ones I've added to my own quotes file: I've been around long enough to have seen an endless parade of magic new techniques du jour, most of which purport to remove the necessity of thought about your programming problem. In the end they wind up contributing one or two pieces to the collective wisdom, and fade away in the rearview mirror. -- Walter Bright Making non-nullable pointers is just plugging one hole in a cheese grater. -- Walter Bright Here's a funny one: My father told me I wasn't at all afraid of hard work. I could lie down right next to it and go to sleep. -- Walter Bright T -- This is a tpyo.
Aug 04
parent IGotD- <nise nise.com> writes:
On Wednesday, 4 August 2021 at 22:42:56 UTC, H. S. Teoh wrote:
 Here the ones I've added to my own quotes file:
 [..]
Ok, let's not get too OT here. Subject is still about the GC and if you use it in games for example.
Aug 05