September 01, 2022
On Thursday, 1 September 2022 at 18:50:05 UTC, Redwan wrote:
> On Thursday, 1 September 2022 at 18:26:12 UTC, Ali Çehreli wrote:
>> On 9/1/22 10:59, Redwan wrote:
>>> On Thursday, 1 September 2022 at 13:53:06 UTC, IGotD- wrote:
>>
>>>> If you have any classes in the class you allocate on the stack, the constructor of the class will allocate them on the heap. Basically only the top level class will be on stack.
>>> 
>>> Can you give an example?
>>> 
>>
>> Sorry to jump in but the following program demonstrates this by pointer values:
>>
>> import std.stdio;
>>
>> class A {
>>   int i;
>> }
>>
>> class B {
>>   A a;
>>   int i;
>>
>>   this() {
>>     this.a = new A();
>>   }
>> }
>>
>> void main() {
>>   scope b = new B();
>>   int i;
>>
>>   writeln("on stack: ", &i);
>>   writeln("on stack: ", &b.i);
>>   writeln("on heap : ", &b.a.i);
>> }
>>
>> Ali
>
> how about `scope this.a = new A();`?

It won't compile:

onlineapp.d(21): Error: found `=` instead of statement

try it online here:

https://run.dlang.io/
September 01, 2022
On Thursday, 1 September 2022 at 18:50:05 UTC, Redwan wrote:
> On Thursday, 1 September 2022 at 18:26:12 UTC, Ali Çehreli wrote:
>> import std.stdio;
>>
>> class A {
>>   int i;
>> }
>>
>> class B {
>>   A a;
>>   int i;
>>
>>   this() {
>>     this.a = new A();
>>   }
>> }
>>
>> void main() {
>>   scope b = new B();
>>   int i;
>>
>>   writeln("on stack: ", &i);
>>   writeln("on stack: ", &b.i);
>>   writeln("on heap : ", &b.a.i);
>> }
>>
>> Ali
>
> how about `scope this.a = new A();`?

If you want everything on the stack, you have to pass in `a` as an argument, like this:

class A {}

class B {
  A a;

  this(A a) {
    this.a = a;
  }
}

void main() {
  scope a = new A(); // on stack
  scope b = new B(a); // on stack
}
September 01, 2022
On Thursday, 1 September 2022 at 19:27:13 UTC, Paul Backus wrote:
>
> If you want everything on the stack, you have to pass in `a` as an argument, like this:
>
> class A {}
>
> class B {
>   A a;
>
>   this(A a) {
>     this.a = a;
>   }
> }
>
> void main() {
>   scope a = new A(); // on stack
>   scope b = new B(a); // on stack
> }

I previously saw an example that allocated the space in the class for the member class, unfortunately I cannot find it. Then it runs emplace in order to run the constructor. This way you don't need to allocate it outside the top level stack, which is annoying when you have many of them.
September 01, 2022

On Thursday, 1 September 2022 at 13:23:42 UTC, Steven Schveighoffer wrote:

>

On 9/1/22 6:13 AM, Redwan wrote:

>

OK tnx. another problem that probably is related to this issue.
I compiled this worthless code:

void main() {}

also this one:

@nogc void main() {}

the valgrind result:

...
total heap usage: 143 alloc, 141 frees, 13,236 bytes allocated
...

!!!
what's this means??
from where comes this allocations and also leaks???

The runtime does some allocations before running main. But these are all C malloc allocations and not GC allocations. There should be zero GC usage in these programs.

Hi Steven,
I think you would agree that one hundred and forty three allocations (=malloc calls?) is a very large (unacceptable) amount for just starting and shutting down the runtime of D.

>

As for "leaks", I think it would tell you that. Looking on the internet, this may count for "reachable" data, that is, data that is allocated, and still referenced at program exit. Such memory is not a "leak" in the sense that you just stopped pointing at it and never freed it.

Matching deallocations should also be required of a language runtime. Every user is forced to use the druntime, it is not an optional component (yes -betterC, come on). One example mentioned on StackOverflow is the case of a DLL [1].

regards,
Johan

[1] https://stackoverflow.com/questions/3840582/still-reachable-leak-detected-by-valgrind#comment90930092_3857638

September 01, 2022
On 9/1/22 12:45, IGotD- wrote:

> an example that allocated the space in the class for
> the member class

I am experimenting with a similar idea where the user can ask a type to have a buffer as a member:

struct S(T, size_t memberCapacity = size_t.max) {
  static if (memberCapacity != size_t.max) {
    // The user wants a member array
    T[memberCapacity] arr;

    void initMemberArray() {
      // Real work with 'arr'...
    }

  } else {
    void initMemberArray() {
      // No work needed in this case
    }
  }

  // ...
}

void main() {
  auto a = S!int();
  auto b = S!(int, 42)();

  pragma(msg, a.sizeof);  // 1
  pragma(msg, b.sizeof);  // 168
}

Ali

September 01, 2022

On 9/1/22 4:11 PM, Johan wrote:

>

On Thursday, 1 September 2022 at 13:23:42 UTC, Steven Schveighoffer wrote:

>

On 9/1/22 6:13 AM, Redwan wrote:

>

OK tnx. another problem that probably is related to this issue.
I compiled this worthless code:

void main() {}

also this one:

@nogc void main() {}

the valgrind result:

...
total heap usage: 143 alloc, 141 frees, 13,236 bytes allocated
...

!!!
what's this means??
from where comes this allocations and also leaks???

The runtime does some allocations before running main. But these are all C malloc allocations and not GC allocations. There should be zero GC usage in these programs.

Hi Steven,
  I think you would agree that one hundred and forty three allocations (=malloc calls?) is a very large (unacceptable) amount for just starting and shutting down the runtime of D.

I think it's malloc and realloc. No I don't think that is too much. How much would be acceptable for you?

One thing I can think of that I was personally involved with that does allocations is the module sorting algorithm (used for detecting cycles and proper ordering of module ctor/dtor). This allocates and deallocate temporary structures to do the directed graph sorting. 143 seems like quite a lot for that, I would still be interested to see what all the exact allocations are.

It also probably allocates the string array for the main args.

> >

As for "leaks", I think it would tell you that. Looking on the internet, this may count for "reachable" data, that is, data that is allocated, and still referenced at program exit. Such memory is not a "leak" in the sense that you just stopped pointing at it and never freed it.

Matching deallocations should also be required of a language runtime. Every user is forced to use the druntime, it is not an optional component (yes -betterC, come on). One example mentioned on StackOverflow is the case of a DLL [1].

The allocation done by rt_init should be deallocated by rt_term, and clearly it's not. If there is not a bug report on that, there should be.

The ones done by pragma(crt_constructor) I don't know how that works in terms of having dlls. So maybe that one is OK.

On a somewhat related note, I wish that there would be a way to avoid the module constructor sorting at runtime, because it is the same every time, and a waste of CPU cycles to do it. But this can only be done after linking. If there were some way to preallocate space for the module ctor cycle order, and then run a post-build step to edit that graph, it would be a great improvement to have.

-Steve

September 01, 2022
On 9/1/2022 4:58 PM, Steven Schveighoffer wrote:
> On a somewhat related note, I wish that there would be a way to avoid the module constructor sorting at runtime, because it is the same every time, and a waste of CPU cycles to do it. But this can only be done *after* linking. If there were some way to preallocate space for the module ctor cycle order, and then run a post-build step to edit that graph, it would be a great improvement to have.

How many modules are in your program?

September 01, 2022
On 9/1/2022 10:50 AM, Paul Backus wrote:
> Recently, we had someone in the community Discord ask for help tracking down a memory leak in their D project, which used the GC.

The -profile=gc can be used to track GC allocations.
September 02, 2022

On 9/2/22 12:23 AM, Walter Bright wrote:

>

On 9/1/2022 4:58 PM, Steven Schveighoffer wrote:

>

On a somewhat related note, I wish that there would be a way to avoid the module constructor sorting at runtime, because it is the same every time, and a waste of CPU cycles to do it. But this can only be done after linking. If there were some way to preallocate space for the module ctor cycle order, and then run a post-build step to edit that graph, it would be a great improvement to have.

How many modules are in your program?

What do you mean? If you are suggesting that probably the module sorting is insignificant, it definitely is not very intensive.

What I don't like about it is that it is a sort of immutable data. In other words, the data does not change from one run to the next, but it's stored unordered, and then every time the program loads, we have to order it. Every time a DLL is loaded, this algorithm needs to be run.

It would be nice if it were stored in the order needed, so no sorting is needed. The sorting algorithm is complex as well, it's not a simple quicksort.

-Steve

September 02, 2022
On 9/2/2022 6:23 AM, Steven Schveighoffer wrote:
> What do you mean? If you are suggesting that probably the module sorting is insignificant, it definitely is not very intensive.

I am indeed suggesting it is insignificant.

> What I don't like about it is that it is a sort of immutable data. In other words, the data does not change from one run to the next, but it's stored unordered, and then every time the program loads, we have to order it. Every time a DLL is loaded, this algorithm needs to be run.
> 
> It would be nice if it were stored in the order needed, so no sorting is needed. The sorting algorithm is complex as well, it's not a simple quicksort.

In the olden days, I (and others) would just have the executable self-patch itself. But such behavior was then banned by the OS.