25

I'm a C++ programmer thats considering using D for a personal project I want to play around with. I was wondering if there's a way to completely disable the garbage collector, and what the risks are of doing so.

I know I can manage my own memory by overriding new and delete to use malloc and free, but if I did that I'd rather the garbage collector not run at all.

he_the_great
  • 6,554
  • 2
  • 30
  • 28
BigSandwich
  • 2,768
  • 2
  • 22
  • 26
  • 1
    We had this discussion in university in one of our lectures, and someone complained about the gc in java, and how much better it is in C++ and C, and how stupid java is, and so on. The professor looked at him and asked one question: "Do you think you can manage memory more efficient than a machine?" – bl4ckb0l7 Jan 23 '09 at 08:13
  • 1
    The answerer is that you have more info. For a computer to do the same/better than you, it needs to back out this info and reason about it. OTOH, while people can do it, it's hard work and easy to get wrong. – BCS Jan 23 '09 at 16:38
  • 3
    Yes, but this project will be a game and games have strict performance requirements. I can't have the GC deciding to run in the middle of a frame. – BigSandwich Jan 23 '09 at 19:26
  • 17
    "Do you think you can manage memory more efficient than a machine?" Yes, I'm a programmer. Some programmer wrote the java GC. Thats not the only way to manage memory. – BigSandwich Jan 23 '09 at 19:28
  • 1
    FWIW, GC is often *faster* than the equivalent manual malloc/free. If you have benchmarked your app and see that the GC is what's slowing it down, then turn it off. But since this is the real world, that is not going to be your problem. – jrockway Jan 23 '09 at 19:59
  • Have a look at this http://www.digitalmars.com/d/2.0/cppstrings.html. Scroll down and read the benchmarks comparing it with c++. – Tim Matthews Jan 24 '09 at 05:09
  • 9
    Thats great, except that I don't care about string perf. Also, It just shows that D's string implementation is better than STLport's. The fact that D strings are reference types surely has more to do with the perf increase than the GC, although GC makes that easier. – BigSandwich Jan 28 '09 at 22:18
  • 24
    Also, I REALLY dislike the attitude that you know the domain of my problem better than I do. I didn't come here for a religious debate about GC. I asked a very specific question. I'd appreciate if someone with higher rep could get rid of all this OT noise. – BigSandwich Jan 28 '09 at 22:28
  • 1
    @BigSandwich: I can certainly appreciate your view, and don't disagree. But I do want to point out that on a mid-level dual core system I am seeing GC times consistently in the 1-3 ms range and never more than about 6 or 7 while under load (in Java); can your game really not tolerate that? – Lawrence Dol Feb 03 '09 at 04:20
  • 10
    If your running at 60fps, 1-3 ms is 6 - 18% of a frame. That's a noticeable spike when the GC runs. Also remember that an inconsistent high frame rate can be worse than a consistent low frame rate. So either I have frame spikes or just a lower all around rate that looks smoother. – BigSandwich Feb 03 '09 at 16:24
  • @BigS - fair enough. I just wondered, since I have played a number of games in Java and have *never* noticed a GC pause. – Lawrence Dol Feb 04 '09 at 06:00
  • Probably because they use free lists and the like, so that there isn't a lot of garbage to clean up Software Monkey. See here: http://www.gamasutra.com/php-bin/news_index.php?story=15211 – BigSandwich Feb 04 '09 at 09:29
  • Sorry, Ctrl Alt D-1337 your post was informative. I think bitschnau and jrockway's post was especially annoying. If its not my problem, then whose is it? – BigSandwich Feb 04 '09 at 09:34
  • More on Schizoid and the problems they had with GC: http://www.gamedevblog.com/2007/03/some_answers.html – BigSandwich Feb 04 '09 at 09:39

4 Answers4

43

To turn off the GC in D2:

import core.memory;

void main(string[] args) {
    GC.disable;
    // Do stuff.
}

If using D1/Phobos:

import std.gc;

void main(char[][] args) {
    std.gc.disable;
    // Do stuff.
}

In D1/Tango:

import tango.core.Memory;

void main(char[][] args) {
    GC.disable;
    // Do stuff.
}

The GC can be reenabled similarly by calling GC.enable (D2 or D1/Tango) or std.gc.enable (D1/Phobos). These can be done at any point in a program. Internally, a counter is used, and to actually reenable GC, you must call enable() once for every time disable() was called.

Here are some things not to do with GC disabled, because they will cause memory leaks:

  1. Do not use the array append ( ~= ) operator, or use the .length property to enlarge an array that has already been allocated. These rely on GC to free the old array if it has to be reallocated, since there may be aliasing to it somewhere else in the program.
  2. Do not use builtin associative arrays. The only way to free these is by GC.
  3. Most of Phobos and, I believe, Tango, were designed with the assumption that garbage collection is present. Functions in these libraries may leak memory horribly if used w/o GC.
  4. Do not use D2 closures with GC disabled. (Not that you would anyway, for a game.)

That said, while D is designed to be usable with the GC disabled in a few critical pieces of code (the kind of critical pieces where real time constraints exist and you probably shouldn't be using any form of malloc not explicitly designed for real time computing anyhow), it was largely designed with the assumption that GC would be present. In your case, you can still use GC for all of the initialization stuff, etc. and only disable it when you hit the part of your game that actually needs to be real time.

As a side note, GC and manual memory management can coexist in D, and in practice, when optimizing code, manually deleting some large objects with trivial lifetimes can result in significant speedups. This can be done similarly to C++, using a delete statement, and is safe to do even if the GC is enabled. When you don't have real time constraints, this gives you most of the benefits of GC with most of the performance of manual memory management.

dsimcha
  • 67,514
  • 53
  • 213
  • 334
  • 25
    Thanks for answering the question I actually asked, instead of assuming that I don't know what I'm doing. – BigSandwich Jan 28 '09 at 22:20
  • As discovered by Benjamin Thaut: do not use homogeneous variadic functions calls. – ponce Jan 07 '13 at 23:08
  • `GC.disable` does not disable the Garbage Collector, it merely suspends Garbage Collection. The Garbage Collector and it's heap are still there. – rustyx May 22 '16 at 07:31
8

If you want to use malloc and free use std.c.stdlib. GC will never touch these. std.gc has all the stuff you will need for memory management including disable().

GC isn't a bad thing though. Most if not nearly all libraries in D will have somewhere in the code where memory is not explicitly deleted so it won't make you a hero to have it allways off but ok if you have some critical performance requirement.

GC makes everything a lot more productive like array slicing and creating new objects in parameters without having the caller store a reference anywhere to them. Good code is a lot less of it and with GC code becomes a lot smaller.

Tim Matthews
  • 5,031
  • 8
  • 38
  • 45
  • There are language features that expect a GC, string concatenation and hashtables are a couple. I'm not sure what they all were. – he_the_great Jan 23 '09 at 15:43
  • One cases where turning off the GC would be valid is where you can show that you won't use up more ram than is to be had. – BCS Jan 23 '09 at 16:31
  • I doubt I'll really be doing a lot of array slicing or string manipulation. Is there a list of language features that depend on the GC? Maybe I should just leave it on and then avoid those features. – BigSandwich Jan 23 '09 at 19:29
  • @BCS GC is not really about amount of ram used so I would disagree with that yet does provide a nice safety net. – Tim Matthews Jan 24 '09 at 03:05
  • @BS: I would go with the route of leaving it on and avoiding things that need GC - seems safer than inadvertently leaking small amounts of memory over time. – Lawrence Dol Feb 11 '09 at 07:35
2

I was reading about D language and I found this in the specs that seems new in D:

40. Better C

-betterC is a command-line flag for dmd, which restricts the compiler's support of certain runtime features. Notably, D programs or libraries compiled with betterC aren't linked with Druntime. The use of compile-time features is not restricted in any way. https://dlang.org/spec/betterc.html

One of the consequence of using this command-line flag is to disable GC and language features relaying on it.

40.1 Consequences

As no Druntime is available, many D features won't work. For example:

  • Garbage Collection
  • Thread-local storage
  • TypeInfo and ModuleInfo
  • Classes
  • Built-in threading (e.g. core.thread)
  • Dynamic arrays (but not slices) and associative arrays
  • Exceptions
  • switch with strings
  • final switch
  • synchronized and core.sync
  • Static module constructors or deconstructors
  • Struct deconstructors
  • unittest (testing can be as usual with the -betterC flag)

see also https://dlang.org/blog/2017/08/23/d-as-a-better-c/

kuroneko
  • 425
  • 2
  • 4
  • 10
1

The GC can be removed and replaced with a simple wrapper around malloc/free.

BCS
  • 75,627
  • 68
  • 187
  • 294
  • No it really can't. A big chunk of the D language and it's runtime won't work to the point the language becomes unusable. – rustyx May 22 '16 at 07:41