On Tuesday, 19 September 2017 at 15:11:31 UTC, Craig Black wrote:
Thank you for the information. What I would like to do is to create an Array template class that doesn't use GC at all.

You want to ensure that it can never refer to GC memory. The type system does not contain that information. It doesn't say whether an object was allocated on the GC heap, on the stack, using malloc, using a whole page of memory with mmap, using hardware addresses directly on an embedded system with manually planned memory layout, using a well-known address range like VGA, as part of the binary's static data segment...

So @nogc can't help you. You could, however, replace the GC implementation with one that throws an AssertError whenever the GC runs a collection, allocates memory, etc. Or you could just add @nogc to your main function.

If you want to forbid all reference types, you could write a `containsReferenceTypes` template, something like:

enum containsReferenceTypes(T) =
  is(T == class) ||
  is(T == interface) ||
  isDynamicArray!T ||
  isDelegate!T ||
  (isStruct!T && hasReferenceField!T);

bool hasReferenceField(T)()
{
  static foreach (t; Fields!T)
  {
    if (containsReferenceTypes!t) return true;
  }
  return false;
}

struct Array(T) if (!containsReferenceTypes!T)
{
}

Unfortunately I don't think this is possible with D in its current state, at least not safely anyway. As it is, I can't prevent someone using my Array template to create an array of objects that reference the GC heap. This means that in order to not break the language and avoid memory leaks, I am forced to tell the GC to scan all of my allocations. There seems to be no way to avoid this unnecessary overhead.

That's use-after-free, not memory leaks. The GC doesn't watch to see when things go out of scope; it periodically scans the world to see what's still in scope.

I realize that the GC will not collect during a @nogc function.
This is a good guarantee, but I want to reduce the amount of time it takes to perform a collection, and there doesn't seem to be a good way to do this.

The GC is smart enough to not scan something for pointers if it doesn't contain pointers. So if you have `new Vec4[100]`, for instance, the GC isn't going to waste time scanning the memory it points to.

So if you have an Array!int variable in a GC'd object, it's basically a pointer and a length. The GC will note that the block of memory it points to has a reference to it and should not be disposed of. It will at some point consider doing a scan on that block of memory, see that it has no pointers in it, and skip over it.

Reply via email to