Garbage collection

2020-06-27 Thread James Gray via Digitalmars-d-learn
I am writing a web application using vibe.d (not sure whether 
that is relevant or not), and have run into a memory leak. I 
wrote the following code to try and replicate the problem.


import std.algorithm;
import std.range;
import std.format;
import std.stdio;
import core.thread;
import core.memory;

auto f(R)(R r) {
 return format("%s", r);
}

void main()
{
 while(true)
 {
  writeln("Starting");
  {
   auto str = f(iota(1).map!(x=>x+1));
  }
  writeln("Done");
  GC.collect();
  Thread.sleep( dur!("msecs")( 3 ) );
 }
}

 It doesn't replicate the problem but it still doesn't behave as 
I would expect. I would expect the memory usage of this code to 
grow and shrink. However, I find that the memory usage grows to 
about 1.5GB and never decreases. Is there something I am not 
understanding?


Garbage Collection Issue

2020-05-30 Thread Marius Cristian Baciu via Digitalmars-d-learn
I am encountering a strange problem with the GC on a specific 
platform:
at the first attempt to clear the current memory pool to make 
room for a new allocation, the GC considers that the page in 
which the main thread resides (the one created in the init 
function of the GC) can be freed.. therefore, frees the entire 
pool and reallocates at the same location; later, when accessing 
thread's address, it stumbles upon garbage data.
The question is: where does the GC expects the address of the 
thread to be found so that it takes it into consideration?
A relevant mention would be that the platform doesn't support TLS 
so it won't find anything when trying to access that data. Could 
it be related to this?


Re: Garbage collection

2020-06-27 Thread James Gray via Digitalmars-d-learn

On Saturday, 27 June 2020 at 10:08:15 UTC, James Gray wrote:
I am writing a web application using vibe.d (not sure whether 
that is relevant or not), and have run into a memory leak. I 
wrote the following code to try and replicate the problem.


[...]


I now compiled the same code above with ldc2 and it is leaking.
Any suggestions?



Re: Garbage collection

2020-06-27 Thread Stanislav Blinov via Digitalmars-d-learn

On Saturday, 27 June 2020 at 10:08:15 UTC, James Gray wrote:

I find that the memory usage grows to about 1.5GB and never 
decreases. Is there something I am not understanding?


How are you measuring that? GC.collect() does not necessarily 
release the pages to the OS. For that, there's the GC.minimize().


Re: Garbage collection

2020-06-27 Thread James Gray via Digitalmars-d-learn

On Saturday, 27 June 2020 at 11:00:58 UTC, Stanislav Blinov wrote:

On Saturday, 27 June 2020 at 10:08:15 UTC, James Gray wrote:

I find that the memory usage grows to about 1.5GB and never 
decreases. Is there something I am not understanding?


How are you measuring that? GC.collect() does not necessarily 
release the pages to the OS. For that, there's the 
GC.minimize().


I am measuring the memory usage using top from the command line.
GC.minimize() does seem to stop the leak. But it doesn't explain 
why
the program isn't releasing essentially all the memory between 
calls
to f (it using around 2GB ram all the time). Is there a way of 
achieving that?


Re: Garbage collection

2020-06-27 Thread Mike Parker via Digitalmars-d-learn

On Saturday, 27 June 2020 at 11:11:38 UTC, James Gray wrote:



I am measuring the memory usage using top from the command line.
GC.minimize() does seem to stop the leak. But it doesn't 
explain why
the program isn't releasing essentially all the memory between 
calls
to f (it using around 2GB ram all the time). Is there a way of 
achieving that?


It's not a leak. The GC allocates memory as it needs it and holds 
on to it. When something is collected, the GC can reuse then 
released memory when it needs it.


Re: Garbage collection

2020-06-27 Thread Stanislav Blinov via Digitalmars-d-learn

On Saturday, 27 June 2020 at 11:11:38 UTC, James Gray wrote:


I am measuring the memory usage using top from the command line.
GC.minimize() does seem to stop the leak.


That is not a memory leak. That's the allocator keeping pages for 
itself to not have to go to the kernel every time you allocate.


But it doesn't explain why the program isn't releasing 
essentially all the memory between calls to f (it using around 
2GB ram all the time).


Allocators usually don't do that. They keep (at least some) 
memory mapped to make allocations more efficient.



Is there a way of achieving that?


I would think collect + minimize should do the trick. Just keep 
in mind that that's grossly inefficient.


Re: Garbage collection

2020-06-27 Thread Arafel via Digitalmars-d-learn

On 27/6/20 13:21, Stanislav Blinov wrote:


I would think collect + minimize should do the trick. Just keep in mind 
that that's grossly inefficient.


If you are using linux, have in mind that the memory is often not 
returned to the OS even after a (libc) free. If you check with tools 
like `top`, it'll still show as assigned to the process.


What I had to do (both in D and in C/C++) was to call malloc_trim [1] 
manually to have the memory actually sent back to the OS.


[1]: https://man7.org/linux/man-pages/man3/malloc_trim.3.html


Re: Garbage collection

2020-06-27 Thread Stanislav Blinov via Digitalmars-d-learn

On Saturday, 27 June 2020 at 11:35:12 UTC, Arafel wrote:

If you are using linux, have in mind that the memory is often 
not returned to the OS even after a (libc) free.


That's a good observation. Although a GC implementation is not 
required to actually use malloc, so depending on that falls into 
"know what you're doing" territory :)


Re: Garbage collection

2020-06-27 Thread James Gray via Digitalmars-d-learn

On Saturday, 27 June 2020 at 12:07:19 UTC, Stanislav Blinov wrote:

On Saturday, 27 June 2020 at 11:35:12 UTC, Arafel wrote:

If you are using linux, have in mind that the memory is often 
not returned to the OS even after a (libc) free.


That's a good observation. Although a GC implementation is not 
required to actually use malloc, so depending on that falls 
into "know what you're doing" territory :)


Thanks for the help, but unfortunately it isn't stopping memory 
usage growing in the original app. I will try and build a minimal 
example. In the meantime perhaps someone can suggest how I might 
figure out what is going on. Repeating the same action is giving 
memory usage growth as follows. 1.7GB first time (which now drops 
to about 1GB), then 2.7GB dropping to about 2GB and so on.


Re: Garbage collection

2020-06-27 Thread James Gray via Digitalmars-d-learn

On Saturday, 27 June 2020 at 12:53:01 UTC, James Gray wrote:
On Saturday, 27 June 2020 at 12:07:19 UTC, Stanislav Blinov 
wrote:

On Saturday, 27 June 2020 at 11:35:12 UTC, Arafel wrote:


[...]


That's a good observation. Although a GC implementation is not 
required to actually use malloc, so depending on that falls 
into "know what you're doing" territory :)


Thanks for the help, but unfortunately it isn't stopping memory 
usage growing in the original app. I will try and build a 
minimal example. In the meantime perhaps someone can suggest 
how I might figure out what is going on. Repeating the same 
action is giving memory usage growth as follows. 1.7GB first 
time (which now drops to about 1GB), then 2.7GB dropping to 
about 2GB and so on.


Which eventually results in mac os running out of memory.


Re: Garbage collection

2020-06-27 Thread kinke via Digitalmars-d-learn

On Saturday, 27 June 2020 at 10:08:15 UTC, James Gray wrote:

have run into a memory leak


Something seems really off indeed. I've run this on Win64 with 
DMD (2.092) and LDC (1.22), without any extra cmdline options:


-
import core.memory;
import core.stdc.stdio;
import std.range;
import std.format;

auto f(R)(R r) { return format("%s", r); }

int toMB(ulong size) { return cast(int) (size / 1048576.0 + 0.5); 
}


void printGCStats()
{
const stats = GC.stats;
const used = toMB(stats.usedSize);
const free = toMB(stats.freeSize);
const total = toMB(stats.usedSize + stats.freeSize);
printf("  GC stats: %dM used, %dM free, %dM total\n", used, 
free, total);

}

void main()
{
printGCStats();

while (true)
{
puts("Starting");
string str = f(iota(100_000_000));
printf("  string size: %dM\n", toMB(str.length));
str = null;
GC.collect();
printGCStats();
}
}
-

Output with DMD (no change with the precise GC via 
`--DRT-gcopt=gc:precise`):

-
  GC stats: 0M used, 1M free, 1M total
Starting
  string size: 943M
  GC stats: 1168M used, 1139M free, 2306M total
Starting
  string size: 943M
  GC stats: 1168M used, 2456M free, 3623M total
Starting
  string size: 943M
  GC stats: 1168M used, 2456M free, 3623M total
Starting
  string size: 943M
  GC stats: 1168M used, 2456M free, 3623M total
Starting
  string size: 943M
  GC stats: 1168M used, 2456M free, 3623M total
-

With LDC:
-
  GC stats: 0M used, 1M free, 1M total
Starting
  string size: 943M
  GC stats: 1168M used, 1139M free, 2306M total
Starting
  string size: 943M
  GC stats: 2335M used, 1288M free, 3623M total
Starting
  string size: 943M
  GC stats: 2335M used, 2605M free, 4940M total
Starting
  string size: 943M
  GC stats: 2335M used, 2605M free, 4940M total
Starting
  string size: 943M
  GC stats: 2335M used, 2605M free, 4940M total
-

Note that I explicitly clear the `str` slice before GC.collect(), 
so that the stack shouldn't contain any refs to the fat string 
anymore.


Re: Garbage collection

2020-06-27 Thread kinke via Digitalmars-d-learn

=> https://issues.dlang.org/show_bug.cgi?id=20983


Re: Garbage collection

2020-06-27 Thread James Gray via Digitalmars-d-learn

On Saturday, 27 June 2020 at 14:12:09 UTC, kinke wrote:

On Saturday, 27 June 2020 at 10:08:15 UTC, James Gray wrote:

have run into a memory leak


Something seems really off indeed. I've run this on Win64 with 
DMD (2.092) and LDC (1.22), without any extra cmdline options:


-
import core.memory;
import core.stdc.stdio;
import std.range;
import std.format;

auto f(R)(R r) { return format("%s", r); }

int toMB(ulong size) { return cast(int) (size / 1048576.0 + 
0.5); }


void printGCStats()
{
const stats = GC.stats;
const used = toMB(stats.usedSize);
const free = toMB(stats.freeSize);
const total = toMB(stats.usedSize + stats.freeSize);
printf("  GC stats: %dM used, %dM free, %dM total\n", used, 
free, total);

}

void main()
{
printGCStats();

while (true)
{
puts("Starting");
string str = f(iota(100_000_000));
printf("  string size: %dM\n", toMB(str.length));
str = null;
GC.collect();
printGCStats();
}
}
-

Output with DMD (no change with the precise GC via 
`--DRT-gcopt=gc:precise`):

-
  GC stats: 0M used, 1M free, 1M total
Starting
  string size: 943M
  GC stats: 1168M used, 1139M free, 2306M total
Starting
  string size: 943M
  GC stats: 1168M used, 2456M free, 3623M total
Starting
  string size: 943M
  GC stats: 1168M used, 2456M free, 3623M total
Starting
  string size: 943M
  GC stats: 1168M used, 2456M free, 3623M total
Starting
  string size: 943M
  GC stats: 1168M used, 2456M free, 3623M total
-

With LDC:
-
  GC stats: 0M used, 1M free, 1M total
Starting
  string size: 943M
  GC stats: 1168M used, 1139M free, 2306M total
Starting
  string size: 943M
  GC stats: 2335M used, 1288M free, 3623M total
Starting
  string size: 943M
  GC stats: 2335M used, 2605M free, 4940M total
Starting
  string size: 943M
  GC stats: 2335M used, 2605M free, 4940M total
Starting
  string size: 943M
  GC stats: 2335M used, 2605M free, 4940M total
-

Note that I explicitly clear the `str` slice before 
GC.collect(), so that the stack shouldn't contain any refs to 
the fat string anymore.


Thank you for doing this. I hope my example doesn't obscure what 
you show here.

(I borrowed some of your code).

I have produced something which essentially reproduces my problem.

---
import std.range;
import std.algorithm;
import std.format;
import std.stdio;
import core.thread;
import core.memory;


struct Node {
 Node* next;
 Node* prev;
 ulong val;
}

Node* insertAfter(Node* cur, ulong val) {
 Node* node = new Node;
 if (cur != null) {
  node.next = cur.next;
  node.prev = cur;
  cur.next = node;
  node.next.prev = node;
 }
 else {
  node.next = node;
  node.prev = node;
 }
 node.val = val;
 return node;
}

int toMB(ulong size) { return cast(int) (size / 1048576.0 + 0.5); 
}


void printGCStats()
{
 const stats = GC.stats;
 const used = toMB(stats.usedSize);
 const free = toMB(stats.freeSize);
 const total = toMB(stats.usedSize + stats.freeSize);
 writef("  GC stats: %dM used, %dM free, %dM total\n", used, 
free, total);

}


void main()
{
 while(true)
 {
  printGCStats();
  writeln("Starting");
  Node* dll;
  dll = iota(2).fold!((c,x)=>insertAfter(c,x))(dll);
  writef("Last element %s\n", dll.val);
  dll = null;
  writeln("Done");
  GC.collect();
  GC.minimize();
  Thread.sleep( dur!("msecs")( 1 ) );
 }
}
--
With DMD this produces:

  GC stats: 0M used, 0M free, 0M total
Starting
Last element 1
Done
  GC stats: 6104M used, 51M free, 6155M total
Starting
Last element 1
Done
  GC stats: 12207M used, 28M free, 12235M total

With LDC2 this produces:

  GC stats: 0M used, 0M free, 0M total
Starting
Last element 1
Done
  GC stats: 6104M used, 51M free, 6155M total
Starting
Last element 1
Done
  GC stats: 12207M used, 28M free, 12235M total







Re: Garbage collection

2020-06-27 Thread Stanislav Blinov via Digitalmars-d-learn

On Saturday, 27 June 2020 at 14:12:09 UTC, kinke wrote:

Note that I explicitly clear the `str` slice before 
GC.collect(), so that the stack shouldn't contain any refs to 
the fat string anymore.


Hrm... What happens if you call collect() twice?


Re: Garbage collection

2020-06-27 Thread kinke via Digitalmars-d-learn

On Saturday, 27 June 2020 at 15:27:34 UTC, Stanislav Blinov wrote:

On Saturday, 27 June 2020 at 14:12:09 UTC, kinke wrote:

Note that I explicitly clear the `str` slice before 
GC.collect(), so that the stack shouldn't contain any refs to 
the fat string anymore.


Hrm... What happens if you call collect() twice?


Nothing changes, even when collecting 5 times at the end of each 
iteration. In the filed testcase, I've extracted the stack ref to 
a dedicated function, so that there really shouldn't be any refs 
on the stack (this is unoptimized code after all...).


Re: Garbage collection

2020-06-27 Thread Stanislav Blinov via Digitalmars-d-learn

On Saturday, 27 June 2020 at 16:03:12 UTC, kinke wrote:
On Saturday, 27 June 2020 at 15:27:34 UTC, Stanislav Blinov 
wrote:



Hrm... What happens if you call collect() twice?


Nothing changes, even when collecting 5 times at the end of 
each iteration. In the filed testcase, I've extracted the stack 
ref to a dedicated function, so that there really shouldn't be 
any refs on the stack (this is unoptimized code after all...).


Here on Linux, the double collection results in this output:

  GC stats: 0M used, 0M free, 0M total
Starting
  string size: 943M
  GC stats: 0M used, 2306M free, 2306M total
Starting
  string size: 943M
  GC stats: 0M used, 2306M free, 2306M total
Starting
  string size: 943M
  GC stats: 0M used, 2306M free, 2306M total
Starting
  string size: 943M
  GC stats: 0M used, 2306M free, 2306M total


Re: Garbage collection

2020-06-27 Thread James Gray via Digitalmars-d-learn

On Saturday, 27 June 2020 at 14:49:34 UTC, James Gray wrote:

On Saturday, 27 June 2020 at 14:12:09 UTC, kinke wrote:

[...]


Thank you for doing this. I hope my example doesn't obscure 
what you show here.

(I borrowed some of your code).

[...]


In case it helps, setting all the next and previous pointers in 
the link list to null allows the garbage collector to collect in 
the above code.


Re: Garbage collection

2020-06-29 Thread Kagamin via Digitalmars-d-learn

On Saturday, 27 June 2020 at 14:49:34 UTC, James Gray wrote:
I have produced something which essentially reproduces my 
problem.


What is the problem? Do you have a leak or you want to know how 
GC works?


Re: Garbage collection

2020-07-20 Thread James Gray via Digitalmars-d-learn

On Tuesday, 30 June 2020 at 06:16:26 UTC, Kagamin wrote:

On Saturday, 27 June 2020 at 14:49:34 UTC, James Gray wrote:
I have produced something which essentially reproduces my 
problem.


What is the problem? Do you have a leak or you want to know how 
GC works?


I have managed to resolve my problem (which was a memory leak). 
My code uses a large data structure similar to a link list and 
the garbage collector was not collecting it. However,
if I set all the "links" between the nodes in the data structure 
to null it is then collected.


Garbage collection and closures.

2017-06-17 Thread ANtlord via Digitalmars-d-learn
Hello! I can't understand one thing related to closures and 
calling of GC. I have the following demo snippet, where a closure 
is passed to `receive` function in a loop.


bool isDone = false;
while(!isDone)
receive((bool val){ isDone = val });

Is GC called every iteration of this loop?

I know that I can move the code to a method of a struct and make 
the closure and variable "isDone" as fields of the struct. It 
avoids GC calling definitely. But I want to get how many times GC 
is called in case of a closure in a loop.


Thanks.


Re: Garbage Collection Issue

2020-05-31 Thread Steven Schveighoffer via Digitalmars-d-learn

On 5/30/20 9:51 PM, Marius Cristian Baciu wrote:

I am encountering a strange problem with the GC on a specific platform:
at the first attempt to clear the current memory pool to make room for a 
new allocation, the GC considers that the page in which the main thread 
resides (the one created in the init function of the GC) can be freed.. 
therefore, frees the entire pool and reallocates at the same location; 
later, when accessing thread's address, it stumbles upon garbage data.
The question is: where does the GC expects the address of the thread to 
be found so that it takes it into consideration?
A relevant mention would be that the platform doesn't support TLS so it 
won't find anything when trying to access that data. Could it be related 
to this?


I can't imagine much of druntime working at all without TLS. Indeed, it 
is a requirement these days.


I believe that's where these roots are being stored.

-Steve


Re: Garbage Collection Issue

2020-06-01 Thread a11e99z via Digitalmars-d-learn
On Sunday, 31 May 2020 at 16:57:06 UTC, Steven Schveighoffer 
wrote:


I can't imagine much of druntime working at all without TLS. 
Indeed, it is a requirement these days.




TLS is evil for async/await when any thread can execute any fiber 
(case where fiber tied to thread is wrong/dead version of 
async/await cuz 1st thread has 1000 fibers and 2nd only 10)


Re: Garbage Collection Issue

2020-06-01 Thread IGotD- via Digitalmars-d-learn
On Sunday, 31 May 2020 at 16:57:06 UTC, Steven Schveighoffer 
wrote:


I can't imagine much of druntime working at all without TLS. 
Indeed, it is a requirement these days.


I believe that's where these roots are being stored.

-Steve


I would really like if druntime could remove its TLS variables as 
much as possible. TLS is really a complicated solution underneath 
and druntime makes it even more complicated. It requires a hook 
in thread creation since the raw TLS specification only applies 
simple variables that can be initialized using memcpy/memset. Any 
thread that is created outside the druntime will fail if D 
supports "complex" TLS variables.


TLS variables are also slower that normal variables since it 
often requires a system call in order to obtain the variable.


druntime should use stack variables much it can and/or shared 
variables.


If you ever encounter a TLS variable which is global variable in 
D, try to see if you can solve it with a stack or shared variable.






Re: Garbage Collection Issue

2020-06-01 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/1/20 5:53 AM, a11e99z wrote:

On Sunday, 31 May 2020 at 16:57:06 UTC, Steven Schveighoffer wrote:

I can't imagine much of druntime working at all without TLS. Indeed, 
it is a requirement these days.




TLS is evil for async/await when any thread can execute any fiber (case 
where fiber tied to thread is wrong/dead version of async/await cuz 1st 
thread has 1000 fibers and 2nd only 10)


That would require fiber local storage, which I don't know if that is 
supported.


I think fibers jumping between threads is also not supported, but I 
don't know for certain.


-Steve


Re: Garbage Collection Issue

2020-06-01 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/1/20 6:51 AM, IGotD- wrote:

On Sunday, 31 May 2020 at 16:57:06 UTC, Steven Schveighoffer wrote:


I can't imagine much of druntime working at all without TLS. Indeed, 
it is a requirement these days.


I believe that's where these roots are being stored.



I would really like if druntime could remove its TLS variables as much 
as possible. TLS is really a complicated solution underneath and 
druntime makes it even more complicated. It requires a hook in thread 
creation since the raw TLS specification only applies simple variables 
that can be initialized using memcpy/memset. Any thread that is created 
outside the druntime will fail if D supports "complex" TLS variables.


D can use non-D created threads, but they will not be scanned by the GC, 
or run thread static constructors or destructors.




TLS variables are also slower that normal variables since it often 
requires a system call in order to obtain the variable.


I was under the impression that TLS works by altering a global pointer 
during the context switch. I didn't think accessing a variable involved 
a system call.


For sure they are slower than "normal" variables, but how much slower? 
I'm not sure.




druntime should use stack variables much it can and/or shared variables.


druntime does not needlessly use TLS as far as I know. If you find a 
case that can be switched please file a bug report.




If you ever encounter a TLS variable which is global variable in D, try 
to see if you can solve it with a stack or shared variable.


This can only take you so far, when the language uses TLS by default. 
The GC has to support scanning TLS and so it uses TLS to track 
thread-specific data.


What it sounds like to me is that the OP implemented a "get it to 
compile" solution for TLS, and this is not working for him.


There is no removing TLS, because the language uses it directly for 
global variables, and many guarantees are enabled by it.


For instance the array append runtime uses a lock-free TLS cache to 
ensure speedy appending. Without TLS, the global lock would be needed 
for every append.


-Steve


Re: Garbage Collection Issue

2020-06-01 Thread IGotD- via Digitalmars-d-learn
On Monday, 1 June 2020 at 12:37:05 UTC, Steven Schveighoffer 
wrote:


I was under the impression that TLS works by altering a global 
pointer during the context switch. I didn't think accessing a 
variable involved a system call.


For sure they are slower than "normal" variables, but how much 
slower? I'm not sure.




It depends, there several different optimizations possible. This 
is essentially the difference between the -fPIC and -fpie flag 
GNU compilers. -fpie can optimize TLS so that it is an offset 
from a certain register (fs or gs with x86). Otherwise the 
compiler insert __tls_get_addr. Typically shared objects gets 
this call, but the executable can optimize. So if druntime is a 
shared object, it will use __tls_get_addr. TLS variables will not 
be major hit if used moderately, used in a loop, then you will 
certainly see a performance hit.




This can only take you so far, when the language uses TLS by 
default. The GC has to support scanning TLS and so it uses TLS 
to track thread-specific data.




Yes, this was some of the annoyance I had when porting druntime. 
The thread startup code needed to use link library (like 
elf/link.h for linux) in order to obtain the entire TLS area 
(areas because there a several of them). This includes scanning 
sections during startup and it becomes even more complicated with 
runtime loaded modules. Basically there is a lot of boiler plate 
in druntime just for reading the executable format. druntime has 
tons of elf stuff in it just to load a program something I'm not 
too keen on, because it's a lot of code and you need to support 
all the quirks with different CPU archs and operating systems. 
You'd want druntime to be more OS agnostic a let the OS services 
deal with the TLS stuff. The only upside can be that you can have 
a full symbolic stack trace during aborts when a poking in the 
executable formats.


Well, that's how it is because of GC and there is not really any 
way around it. A non tracing GC would not have this requirement 
though. When you dig into these details you realize how heavy the 
D language really is and some solutions get negative beauty 
points.










On D's garbage collection

2019-10-08 Thread Marcel via Digitalmars-d-learn
I'm been thinking about using D in conjunction with C11 to 
develop a set of applications with hard real-time requirements. 
While initially the goal was to use C++ instead, it has become 
clear that D's introspection facilities will offer significant 
advantages. Unfortunately, the project will heavily rely on 
custom memory allocators written in C, so the presence of garbage 
collection in the language is a problem. While I'm aware that the 
nogc attribute exists, I haven't actually seen a way to apply it 
to a whole project. Is this possible?


Dynamic Array Garbage collection

2009-02-24 Thread wolftousen
I have a function defined as:

some_function(int[] array) { ... };  //this function does not ever modify 
values of array

When I call this function (once every program cycle) from an object using an 
array of type short:

//member variable in an object
short[] x = new short[4];

//object calls this
some_function([ x[0], x[1], x[2], x[3] ]);

After a few seconds of the program running, x[0] and x[1] values are set to 0 
and a couple values of another array in the object are modified as well.

I have found that this bug is corrected by calling delete at the end of 
some_function of the variable array.  This tells me that the garbage collector 
is acting funny if I do not call delete on the array.  (I have watched the 
memory usage of the program and it doesn't fluctuate or pause or anything to 
signal the freeing/allocating of memory)

Any Idea what is going on?


Garbage collection in D

2009-06-02 Thread Diwaker Gupta
I've just started to play around with D, and I'm hoping someone can clarify 
this. I wrote a very simple program that just allocates lots of objects, in 
order to benchmark the garbage collector in D. For comparison, I wrote the 
programs in C++, Java and D:
C++: http://gist.github.com/122708
Java: http://gist.github.com/122709
D: http://gist.github.com/121790

With an iteration count of , I get the following numbers:
JAVA:
0:01.60 elapsed, 1.25 user, 0.28 system
C++:
0:04.99 elapsed, 4.97 user, 0.00 system
D:
0:25.28 elapsed, 25.22 user, 0.00 system

As you can see, D is abysmally slow compared to C++ and Java. This is using the 
GNU gdc compiler. I'm hoping the community can give me some insight on what is 
going on.

Thanks,
Diwaker


Re: Garbage collection and closures.

2017-06-17 Thread Adam D. Ruppe via Digitalmars-d-learn

On Saturday, 17 June 2017 at 13:03:28 UTC, ANtlord wrote:

Is GC called every iteration of this loop?


No, it will once on scope entry; where the deepest-referenced 
variable that is actually captured is defined. The compiler 
allocates heap space instead of stack space for the locals, then 
runs the function normally using that space.


The current implementation doesn't quite do this - it actually 
will alloc only once, on function entry, even when there's a 
variable inside a loop that is supposed to be independent. This 
is the cause of the commonly-referenced bug with foreach(i; 
whatever) capture(i); all showing the same number.


When that bug is fixed, it is possible to allocate on each 
loop... but your code doesn't anyway, so you're ok.


It will only alloc once. You can prove this with a debugger btw, 
set a breakpoint on `_d_allocmemory`.


Re: Garbage collection and closures.

2017-06-17 Thread ANtlord via Digitalmars-d-learn

On Saturday, 17 June 2017 at 13:13:17 UTC, Adam D. Ruppe wrote:

On Saturday, 17 June 2017 at 13:03:28 UTC, ANtlord wrote:

Is GC called every iteration of this loop?


No, it will once on scope entry; where the deepest-referenced 
variable that is actually captured is defined. The compiler 
allocates heap space instead of stack space for the locals, 
then runs the function normally using that space.


Excuse me, I can't get what does it mean "deepest-referenced". 
What the deep you mean? The deep of a closure or deep of the 
function where the variable is defined. Can you give an example 
code?


It will only alloc once. You can prove this with a debugger 
btw, set a breakpoint on `_d_allocmemory`.


Is this function called every time when allocation happens in a 
heap?


Thank you. Sorry if my English is not clear.


Re: Garbage collection and closures.

2017-06-17 Thread Adam D. Ruppe via Digitalmars-d-learn

On Saturday, 17 June 2017 at 14:19:34 UTC, ANtlord wrote:
Excuse me, I can't get what does it mean "deepest-referenced". 
What the deep you mean? The deep of a closure or deep of the 
function where the variable is defined. Can you give an example 
code?


Where the variable is defined that is referenced in the closure.

So:

---
void uses(void delegate() dg);

void foo() {
   int a;
   foreach(b; 0 .. 10) {
  uses( () { a++; } ); // #1
  uses( () { b++; } ); // #2
   }
}
---


In that case, #1 would only be allocated once, at the start of 
the foo() function. It only uses `a`, so it doesn't have to 
allocate again after the point a is defined.


But #2 might allocate each time through the loop. (It currently 
doesn't, but this is filed as an open bug because it is supposed 
to.) Since it uses `b` which is defined inside the loop, it will 
have to allocate a new copy for each iteration.


Is this function called every time when allocation happens in a 
heap?


Not any allocation, it is just the function the compiler uses 
when it needs to make a closure.


Re: Garbage collection and closures.

2017-06-17 Thread ANtlord via Digitalmars-d-learn

On Saturday, 17 June 2017 at 17:15:50 UTC, Adam D. Ruppe wrote:

On Saturday, 17 June 2017 at 14:19:34 UTC, ANtlord wrote:
Excuse me, I can't get what does it mean "deepest-referenced". 
What the deep you mean? The deep of a closure or deep of the 
function where the variable is defined. Can you give an 
example code?


Where the variable is defined that is referenced in the closure.

So:

---
void uses(void delegate() dg);

void foo() {
   int a;
   foreach(b; 0 .. 10) {
  uses( () { a++; } ); // #1
  uses( () { b++; } ); // #2
   }
}
---


In that case, #1 would only be allocated once, at the start of 
the foo() function. It only uses `a`, so it doesn't have to 
allocate again after the point a is defined.


But #2 might allocate each time through the loop. (It currently 
doesn't, but this is filed as an open bug because it is 
supposed to.) Since it uses `b` which is defined inside the 
loop, it will have to allocate a new copy for each iteration.


Is this function called every time when allocation happens in 
a heap?


Not any allocation, it is just the function the compiler uses 
when it needs to make a closure.


Thanks a lot, Adam! Everything is clear. Except for the bug. I've 
got an expected result of a value of the variable from #2. The 
value equals to number from sequence plus one in each iteration. 
There are ten iterations.


What's wrong? Are there should be five iterations? It doesn't 
make sense for me due to the variable assigned value from the 
sequence 0..10. Or do I look at the wrong place? Can you give me 
a link to the bug?


Thank you again!


Re: Garbage collection and closures.

2017-06-19 Thread Dsby via Digitalmars-d-learn

On Saturday, 17 June 2017 at 17:15:50 UTC, Adam D. Ruppe wrote:

On Saturday, 17 June 2017 at 14:19:34 UTC, ANtlord wrote:

[...]


Where the variable is defined that is referenced in the closure.

So:

[...]


if the uses parma is 'scope':

void uses(scope void delegate() dg);

will it be not alloc memory?





Re: Garbage collection and closures.

2017-06-19 Thread Dsby via Digitalmars-d-learn

On Monday, 19 June 2017 at 09:10:16 UTC, Dsby wrote:

On Saturday, 17 June 2017 at 17:15:50 UTC, Adam D. Ruppe wrote:

On Saturday, 17 June 2017 at 14:19:34 UTC, ANtlord wrote:

[...]


Where the variable is defined that is referenced in the 
closure.


So:

[...]


if the uses parma is 'scope':

void uses(scope void delegate() dg);

will it be not alloc memory?


I test it , if use scope it will not alloc memony.

import std.stdio;

void call(void delegate() fun)
{
fun();
}

void call2(scope void delegate() fun)
{
fun();
}

void main()
{
int a = 10;
   // call((){writeln(a);});
call2((){writeln(a);});
}
dmd -vgc ./t.d
it will not print anything.

if use call:
void main()
{
int a = 10;
call((){writeln(a);});
   // call2((){writeln(a);});
}

dmd -vgc ./t.d
  
 182ms  2017年06月19日 星期一 17时16分47秒

./t.d(13): vgc: using closure causes GC allocation



Re: Garbage collection and closures.

2017-06-19 Thread Adam D. Ruppe via Digitalmars-d-learn

On Monday, 19 June 2017 at 09:18:56 UTC, Dsby wrote:

void uses(scope void delegate() dg);

will it be not alloc memory?


I test it , if use scope it will not alloc memony.


Right, using `scope` at the point the delegate variable is 
defined means it will never allocate.


Re: On D's garbage collection

2019-10-08 Thread Ferhat Kurtulmuş via Digitalmars-d-learn

On Tuesday, 8 October 2019 at 16:28:51 UTC, Marcel wrote:
I'm been thinking about using D in conjunction with C11 to 
develop a set of applications with hard real-time requirements. 
While initially the goal was to use C++ instead, it has become 
clear that D's introspection facilities will offer significant 
advantages. Unfortunately, the project will heavily rely on 
custom memory allocators written in C, so the presence of 
garbage collection in the language is a problem. While I'm 
aware that the nogc attribute exists, I haven't actually seen a 
way to apply it to a whole project. Is this possible?


I think you may find this interesting: 
https://www.auburnsounds.com/blog/2016-11-10_Running-D-without-its-runtime.html




Re: On D's garbage collection

2019-10-08 Thread Ferhat Kurtulmuş via Digitalmars-d-learn
On Tuesday, 8 October 2019 at 16:43:23 UTC, Ferhat Kurtulmuş 
wrote:

On Tuesday, 8 October 2019 at 16:28:51 UTC, Marcel wrote:
I'm been thinking about using D in conjunction with C11 to 
develop a set of applications with hard real-time 
requirements. While initially the goal was to use C++ instead, 
it has become clear that D's introspection facilities will 
offer significant advantages. Unfortunately, the project will 
heavily rely on custom memory allocators written in C, so the 
presence of garbage collection in the language is a problem. 
While I'm aware that the nogc attribute exists, I haven't 
actually seen a way to apply it to a whole project. Is this 
possible?


I think you may find this interesting: 
https://www.auburnsounds.com/blog/2016-11-10_Running-D-without-its-runtime.html


And the code which is actually working: 
https://github.com/AuburnSounds/Dplug/blob/master/core/dplug/core/nogc.d





Re: On D's garbage collection

2019-10-08 Thread Max Haughton via Digitalmars-d-learn

On Tuesday, 8 October 2019 at 16:28:51 UTC, Marcel wrote:
I'm been thinking about using D in conjunction with C11 to 
develop a set of applications with hard real-time requirements. 
While initially the goal was to use C++ instead, it has become 
clear that D's introspection facilities will offer significant 
advantages. Unfortunately, the project will heavily rely on 
custom memory allocators written in C, so the presence of 
garbage collection in the language is a problem. While I'm 
aware that the nogc attribute exists, I haven't actually seen a 
way to apply it to a whole project. Is this possible?


Do you want to write D code that just doesn't use the GC or the 
whole runtime?


If the former then use @nogc at the entry point of your D code 
(This means that - say - main cannot call anything non-@nogc and 
therefore guarantees the program is @nogc), if the latter then 
use -betterC


IMO, if the interface to your memory allocators is stable then 
just link with them and write the whole thing in D (Interfacing 
with C is a solved problem but C is just awful compared to the 
features you get for free in D)


Re: On D's garbage collection

2019-10-13 Thread Marcel via Digitalmars-d-learn
On Tuesday, 8 October 2019 at 16:48:55 UTC, Ferhat Kurtulmuş 
wrote:
On Tuesday, 8 October 2019 at 16:43:23 UTC, Ferhat Kurtulmuş 
wrote:

On Tuesday, 8 October 2019 at 16:28:51 UTC, Marcel wrote:

[...]


I think you may find this interesting: 
https://www.auburnsounds.com/blog/2016-11-10_Running-D-without-its-runtime.html


And the code which is actually working: 
https://github.com/AuburnSounds/Dplug/blob/master/core/dplug/core/nogc.d


Wonderful, i'll be looking into it. Thank you!


Freeing of memory (garbage collection)

2008-12-08 Thread Dan W
A couple of questions:

1: Even though D has an automatic garbage collector, is one still
allowed to free the memory of a malloced array manually (using free
() ), to avoid pauses in the program?

2: One justification on the website for using automatic garbage
collection is how "allocated memory will only be freed if system RAM
is tight". But surely that's silly, since one may want *lots* of
memory free for a completely different application (merely memory
being 'tight' before freeing may not be good enough - one may want D
to free memory sooner).


Re: Dynamic Array Garbage collection

2009-02-24 Thread Daniel Keep


wolftousen wrote:
> I have a function defined as:
> 
> some_function(int[] array) { ... };  //this function does not ever modify 
> values of array
> 
> When I call this function (once every program cycle) from an object using an 
> array of type short:
> 
> //member variable in an object
> short[] x = new short[4];
> 
> //object calls this
> some_function([ x[0], x[1], x[2], x[3] ]);
> 
> After a few seconds of the program running, x[0] and x[1] values are set to 0 
> and a couple values of another array in the object are modified as well.
> 
> I have found that this bug is corrected by calling delete at the end of 
> some_function of the variable array.  This tells me that the garbage 
> collector is acting funny if I do not call delete on the array.  (I have 
> watched the memory usage of the program and it doesn't fluctuate or pause or 
> anything to signal the freeing/allocating of memory)
> 
> Any Idea what is going on?

This sounds like something else is going on, although what I'm not sure.
  Maybe it's because I just woke up, but I can't see how that code could
compile anyway, since you can't pass a short[] to a function expecting
an int[].  Do you have a minimal, reproducible test case we can look at?

  -- Daniel


Re: Dynamic Array Garbage collection

2009-02-24 Thread Jarrett Billingsley
On Tue, Feb 24, 2009 at 6:45 PM, Daniel Keep
 wrote:

>  Maybe it's because I just woke up, but I can't see how that code could
> compile anyway, since you can't pass a short[] to a function expecting
> an int[].

You missed the array literal.


Re: Dynamic Array Garbage collection

2009-02-24 Thread Daniel Keep


Jarrett Billingsley wrote:
> On Tue, Feb 24, 2009 at 6:45 PM, Daniel Keep
>  wrote:
> 
>>  Maybe it's because I just woke up, but I can't see how that code could
>> compile anyway, since you can't pass a short[] to a function expecting
>> an int[].
> 
> You missed the array literal.

I saw that, but thought that it would be a short[] literal since it's
usually the type of the first argument.

  -- Daniel


Re: Dynamic Array Garbage collection

2009-02-24 Thread Jarrett Billingsley
On Tue, Feb 24, 2009 at 10:42 PM, Daniel Keep
 wrote:
>>
>> You missed the array literal.
>
> I saw that, but thought that it would be a short[] literal since it's
> usually the type of the first argument.

Odd, it works.  And properly too.

I give up on trying to figure out what the compiler does to figure out
the type of array literals :P


Re: Dynamic Array Garbage collection

2009-02-24 Thread grauzone

Jarrett Billingsley wrote:

On Tue, Feb 24, 2009 at 10:42 PM, Daniel Keep
 wrote:

You missed the array literal.

I saw that, but thought that it would be a short[] literal since it's
usually the type of the first argument.


Odd, it works.  And properly too.


Could it be because of integer promotion rules?


I give up on trying to figure out what the compiler does to figure out
the type of array literals :P


Re: Dynamic Array Garbage collection

2009-03-12 Thread Robert Fraser

wolftousen wrote:

I have a function defined as:

some_function(int[] array) { ... };  //this function does not ever modify 
values of array

When I call this function (once every program cycle) from an object using an 
array of type short:

//member variable in an object
short[] x = new short[4];

//object calls this
some_function([ x[0], x[1], x[2], x[3] ]);

After a few seconds of the program running, x[0] and x[1] values are set to 0 
and a couple values of another array in the object are modified as well.

I have found that this bug is corrected by calling delete at the end of 
some_function of the variable array.  This tells me that the garbage collector 
is acting funny if I do not call delete on the array.  (I have watched the 
memory usage of the program and it doesn't fluctuate or pause or anything to 
signal the freeing/allocating of memory)

Any Idea what is going on?


Can you use obj2asm and post the assembly of both functions? I'm 
guessing DMD is doing some kind of weird optimization with the array 
literal allocation.


Re: Dynamic Array Garbage collection

2009-03-12 Thread bearophile
wolftousen wrote:
> some_function([ x[0], x[1], x[2], x[3] ]);

That may also be written:
some_function(x[0 .. 4]);

Bye,
bearophile


Re: Dynamic Array Garbage collection

2009-03-12 Thread Jarrett Billingsley
On Thu, Mar 12, 2009 at 8:09 AM, bearophile  wrote:
> wolftousen wrote:
>> some_function([ x[0], x[1], x[2], x[3] ]);
>
> That may also be written:
> some_function(x[0 .. 4]);

Wrong types.


Re: Dynamic Array Garbage collection

2009-03-12 Thread bearophile
Jarrett Billingsley:
> Wrong types.

Right, I am sorry, thank you for spotting it.
There's the moderate need for a different kind of cast, for collections 
(arrays).
At the moment you can do:

import d.func: map, putr, array, xcast;
import std.conv: toInt;
import d.templates: ArrayType1;

void some_function(int[] x) {
putr(typeid(typeof(x)), " ", x);
}

void main() {
short[] x = [cast(short)10_000, 5_000, 100, 6_000, 50, 950];

some_function(map((ArrayType1!(typeof(x)) s){return cast(int)s;}, x[0 .. 
4]));

// or less DRY:
some_function(map((short s){return cast(int)s;}, x[0 .. 4]));

// better:
some_function(array(xcast!(int)(x[0 .. 4])));
}

The last version with array and xcast may be acceptable. The advantage of using 
it is that the ranges 0..4 can be variables.
Built-in types aren't constructors-functions, so you can't do something like 
this:

some_function(map(&int, x[0 .. 4]));

Bye,
bearophile


Re: Garbage collection in D

2009-06-02 Thread Tim Matthews

Diwaker Gupta wrote:

I've just started to play around with D, and I'm hoping someone can clarify 
this. I wrote a very simple program that just allocates lots of objects, in 
order to benchmark the garbage collector in D. For comparison, I wrote the 
programs in C++, Java and D:
C++: http://gist.github.com/122708
Java: http://gist.github.com/122709
D: http://gist.github.com/121790

With an iteration count of , I get the following numbers:
JAVA:
0:01.60 elapsed, 1.25 user, 0.28 system
C++:
0:04.99 elapsed, 4.97 user, 0.00 system
D:
0:25.28 elapsed, 25.22 user, 0.00 system

As you can see, D is abysmally slow compared to C++ and Java. This is using the 
GNU gdc compiler. I'm hoping the community can give me some insight on what is 
going on.

Thanks,
Diwaker


Can someone try dmd and ldc as gdc is dying (if not already dead). Also 
code in the iterations and take out the command line reading and 
printing so to make it accurate.


Re: Garbage collection in D

2009-06-02 Thread Jarrett Billingsley
On Tue, Jun 2, 2009 at 8:40 PM, Diwaker Gupta  wrote:
> I've just started to play around with D, and I'm hoping someone can clarify 
> this. I wrote a very simple program that just allocates lots of objects, in 
> order to benchmark the garbage collector in D. For comparison, I wrote the 
> programs in C++, Java and D:
> C++: http://gist.github.com/122708
> Java: http://gist.github.com/122709
> D: http://gist.github.com/121790
>
> With an iteration count of , I get the following numbers:
> JAVA:
> 0:01.60 elapsed, 1.25 user, 0.28 system
> C++:
> 0:04.99 elapsed, 4.97 user, 0.00 system
> D:
> 0:25.28 elapsed, 25.22 user, 0.00 system
>
> As you can see, D is abysmally slow compared to C++ and Java. This is using 
> the GNU gdc compiler. I'm hoping the community can give me some insight on 
> what is going on.

D's GC is not nearly as well-developed as that of Java's, and its
performance is not that stellar.  Sorry, but you are not the first to
discover this by any stretch of the imagination.  (On a side note, I
have a feeling you and bearophile will get on famously.)

Also, benchmarking a GC against manual memory management doesn't do
much for you.  It's apples and oranges.  Though it is funny to see how
badly Java beats C++ there.


Re: Garbage collection in D

2009-06-02 Thread BCS

Hello Jarrett,


On Tue, Jun 2, 2009 at 8:40 PM, Diwaker Gupta
 wrote:


I've just started to play around with D, and I'm hoping someone can
clarify this. I wrote a very simple program that just allocates lots
of objects, in order to benchmark the garbage collector in D. For
comparison, I wrote the programs in C++, Java and D:

C++: http://gist.github.com/122708

Java: http://gist.github.com/122709

D: http://gist.github.com/121790

With an iteration count of , I get the following numbers:
JAVA:
0:01.60 elapsed, 1.25 user, 0.28 system
C++:
0:04.99 elapsed, 4.97 user, 0.00 system
D:
0:25.28 elapsed, 25.22 user, 0.00 system
As you can see, D is abysmally slow compared to C++ and Java. This is
using the GNU gdc compiler. I'm hoping the community can give me some
insight on what is going on.


D's GC is not nearly as well-developed as that of Java's, and its
performance is not that stellar.  Sorry, but you are not the first to
discover this by any stretch of the imagination.  (On a side note, I
have a feeling you and bearophile will get on famously.)

Also, benchmarking a GC against manual memory management doesn't do
much for you.  It's apples and oranges.  Though it is funny to see how
badly Java beats C++ there.



Java may be able to tell that the allocation never needs to be kept and is 
just reusing the same space on the stack. Heck it might even not be doing 
that as you can tell that the class only ever holds the same value as i so 
it might just be skipping the new all together.





Re: Garbage collection in D

2009-06-03 Thread Robert Clipsham

Diwaker Gupta wrote:

I've just started to play around with D, and I'm hoping someone can clarify 
this. I wrote a very simple program that just allocates lots of objects, in 
order to benchmark the garbage collector in D. For comparison, I wrote the 
programs in C++, Java and D:
C++: http://gist.github.com/122708
Java: http://gist.github.com/122709
D: http://gist.github.com/121790

With an iteration count of , I get the following numbers:
JAVA:
0:01.60 elapsed, 1.25 user, 0.28 system
C++:
0:04.99 elapsed, 4.97 user, 0.00 system
D:
0:25.28 elapsed, 25.22 user, 0.00 system

As you can see, D is abysmally slow compared to C++ and Java. This is using the 
GNU gdc compiler. I'm hoping the community can give me some insight on what is 
going on.

Thanks,
Diwaker


After porting the D version to tango:

D: 6.282s (ldmd -O5 -inline -release -L-s -singleobj gctest.d)
C++: 4.435s (g++ -O5 gctest.d)

This is on a C2D 2.2Ghz, 2GB RAM, Linux x86-64. I don't have java 
installed, so can't test that. Maybe if you're planning to use the GC a 
lot you should consider using tango?


Re: Garbage collection in D

2009-06-03 Thread TSalm
Le Wed, 03 Jun 2009 02:40:11 +0200, Diwaker Gupta  
 a écrit:


I've just started to play around with D, and I'm hoping someone can  
clarify this. I wrote a very simple program that just allocates lots of  
objects, in order to benchmark the garbage collector in D. For  
comparison, I wrote the programs in C++, Java and D:

C++: http://gist.github.com/122708
Java: http://gist.github.com/122709
D: http://gist.github.com/121790

With an iteration count of , I get the following numbers:
JAVA:
0:01.60 elapsed, 1.25 user, 0.28 system
C++:
0:04.99 elapsed, 4.97 user, 0.00 system
D:
0:25.28 elapsed, 25.22 user, 0.00 system



I think the line 14 in the D source is useless.
On my linux system :

D with line 14 removed :
--
ts...@fgabriel:~/dev/DBenchmark$ time ./Benchmark allocations 
787459713

real0m28.779s
user0m28.778s
sys 0m0.004s

C++:
---
ts...@fgabriel:~/dev/DBenchmark$ time ./a.out allocations 
Ran  allocations of RunAllocations. Final value: 787459713

real0m16.406s
user0m16.405s
sys 0m0.004s

Java :
-
ts...@fgabriel:~/dev/DBenchmark$ time java Benchmark allocations 
Ran  allocations of RunAllocations. Final value: 787459713

real0m6.679s
user0m6.408s
sys 0m0.248s

But with the use of "scope" keyword at line 13 of the D source :
ts...@fgabriel:~/dev/DBenchmark$ time ./Benchmark allocations 
787459713

real0m10.752s
user0m10.753s
sys 0m0.000s


Re: Garbage collection in D

2009-06-03 Thread Robert Clipsham

Robert Clipsham wrote:

After porting the D version to tango:

D: 6.282s (ldmd -O5 -inline -release -L-s -singleobj gctest.d)
C++: 4.435s (g++ -O5 gctest.d)

This is on a C2D 2.2Ghz, 2GB RAM, Linux x86-64. I don't have java 
installed, so can't test that. Maybe if you're planning to use the GC a 
lot you should consider using tango?


After reading TSalm's post, I reran the D version with the scope keyword 
at line 16:


D (with scope): 1.098s
D: 6.282s
C++: 4.435s

It seems by using scope and tango you can easily compete with C++.


Re: Garbage collection in D

2009-06-03 Thread bearophile
Jarrett Billingsley:
> (On a side note, I have a feeling you and bearophile will get on famously.)<

I have found a new friend ;-)

Some timings, usual settings, Core2 2 GHz:

Timings, N=100_000_000, Windows, seconds:
  D 1:  40.20 DMD
  D 2:  21.83 DMD
  D 2:  18.80 DMD, struct + scope
  C++:  18.06
  D 1:   8.47 DMD
  D 2:   7.41 DMD + scope
  Java   1.78 -server
  Java:  1.44
  
Timings, N=100_000_000, Pubuntu, seconds:
  D 1:  25.7  LDC
  C++:   6.87
  D 1:   2.67 LDC + scope
  Java:  1.49

Poor LDC :-)

Bye,
bearophile


Re: Garbage collection in D

2009-06-03 Thread bearophile
I have tried the new JavaVM on Win, that optionally performs escape analysis, 
and the results are nice:

Timings, N=100_000_000, Windows, seconds:
  D 1:  40.20 DMD
  D 2:  21.83 DMD
  D 2:  18.80 DMD, struct + scope
  C++:  18.06
  D 1:   8.47 DMD
  D 2:   7.41 DMD + scope
  Java:  1.84 V.1.6.0_14, -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC
  Java   1.78 -server
  Java:  1.44
  Java:  1.38 V.1.6.0_14
  Java:  0.28 V.1.6.0_14, -server -XX:+DoEscapeAnalysis
  
Timings, N=100_000_000, Pubuntu, seconds:
  D 1:  25.7  LDC
  C++:   6.87
  D 1:   2.67 LDC + scope
  Java:  1.49

Bye,
bearophile


Re: Garbage collection in D

2009-06-03 Thread Rainer Deyke
Robert Clipsham wrote:
> After reading TSalm's post, I reran the D version with the scope keyword
> at line 16:
> 
> D (with scope): 1.098s
> D: 6.282s
> C++: 4.435s
> 
> It seems by using scope and tango you can easily compete with C++.

'scope' eliminates dynamic memory allocation.  At this point you're not
measuring the speed of the garbage collector at all.  For a fair
comparison, you should also eliminate the useless dynamic memory
allocation from the C++ version.


-- 
Rainer Deyke - rain...@eldwood.com


Re: Garbage collection in D

2009-06-03 Thread Robert Fraser

What's the difference between:

  D 1:  40.20 DMD
  D 2:  21.83 DMD
  D 2:  18.80 DMD, struct + scope


and:

  D 1:   8.47 DMD
  D 2:   7.41 DMD + scope


...?


Re: Garbage collection in D

2009-06-03 Thread bearophile
Robert Fraser:

> What's the difference between:
> >   D 1:  40.20 DMD
> >   D 2:  21.83 DMD

That's the standard code.

> and:
> >   D 1:   8.47 DMD
> >   D 2:   7.41 DMD + scope

They are both with scope, on D1 and D2.
Sorry for my small omission.

Bye,
bearophile


Re: Garbage collection in D

2009-06-03 Thread Sam Hu
bearophile Wrote:

> I have tried the new JavaVM on Win, that optionally performs escape analysis, 
> and the results are nice:
> 
> Timings, N=100_000_000, Windows, seconds:
>   D 1:  40.20 DMD
>   D 2:  21.83 DMD
>   D 2:  18.80 DMD, struct + scope
>   C++:  18.06
>   D 1:   8.47 DMD
>   D 2:   7.41 DMD + scope
>   Java:  1.84 V.1.6.0_14, -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC
>   Java   1.78 -server
>   Java:  1.44
>   Java:  1.38 V.1.6.0_14
>   Java:  0.28 V.1.6.0_14, -server -XX:+DoEscapeAnalysis
>   
> Timings, N=100_000_000, Pubuntu, seconds:
>   D 1:  25.7  LDC
>   C++:   6.87
>   D 1:   2.67 LDC + scope
>   Java:  1.49
> 
> Bye,
> bearophile

Sorry for my stepping in...

What does this result mean?Does it mean D is slower than Java and C++ is also 
slower than Java?Or that's true just under  certain circumstance?
I am really confused and really appreicate if any further explanation.


Regards,
Sam


Re: Garbage collection in D

2009-06-03 Thread Robert Fraser

Sam Hu wrote:

bearophile Wrote:


I have tried the new JavaVM on Win, that optionally performs escape analysis, 
and the results are nice:

Timings, N=100_000_000, Windows, seconds:
  D 1:  40.20 DMD
  D 2:  21.83 DMD
  D 2:  18.80 DMD, struct + scope
  C++:  18.06
  D 1:   8.47 DMD
  D 2:   7.41 DMD + scope
  Java:  1.84 V.1.6.0_14, -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC
  Java   1.78 -server
  Java:  1.44
  Java:  1.38 V.1.6.0_14
  Java:  0.28 V.1.6.0_14, -server -XX:+DoEscapeAnalysis
  
Timings, N=100_000_000, Pubuntu, seconds:

  D 1:  25.7  LDC
  C++:   6.87
  D 1:   2.67 LDC + scope
  Java:  1.49

Bye,
bearophile


Sorry for my stepping in...

What does this result mean?Does it mean D is slower than Java and C++ is also 
slower than Java?Or that's true just under  certain circumstance?
I am really confused and really appreicate if any further explanation.


Regards,
Sam


It suggests that for dynamic allocation of many small objects via "new", 
Java is an order of magnitude faster than C++, which in turn is slightly 
faster than D.


Re: Garbage collection in D

2009-06-03 Thread Rainer Deyke
Sam Hu wrote:
> What does this result mean?Does it mean D is slower than Java and C++
> is also slower than Java?Or that's true just under  certain
> circumstance? I am really confused and really appreicate if any
> further explanation.

These are the timings for using dynamic memory allocation:
>>   D 1:  40.20 DMD
>>   D 2:  21.83 DMD
>>   C++:  18.06
>>   Java:  1.38 V.1.6.0_14

Java is the fastest by a large margin because it has the benefit of a
moving garbage collector.  This means allocation is a simple pointer
bump and deallocation is completely free.  The slow aspects of this
garbage collector (detection and preservation) aren't really tested by
this benchmark.

These are the timings without dynamic memory allocation:
>>   D 1:   8.47 DMD [+ scope]
>>   D 2:   7.41 DMD + scope
>>   Java:  0.28 V.1.6.0_14, -server -XX:+DoEscapeAnalysis

D's performance is unexpectedly bad, so much that I expect that it might
be using dynamic memory allocation anyway despite the 'scope' keyword.
Java is clever in that it eliminates unnecessary dynamic memory
allocations automatically.  C++ is notable absent, but I fully expect it
to outperform Java by a significant margin.


-- 
Rainer Deyke - rain...@eldwood.com


Re: Garbage collection in D

2009-06-03 Thread Sam Hu
> D's performance is unexpectedly bad, so much that I expect that it might
> be using dynamic memory allocation anyway despite the 'scope' keyword.

I am sorry to hear that,really,really sorry.


Re: Garbage collection in D

2009-06-04 Thread bearophile
Rainer Deyke:

>The slow aspects of this garbage collector (detection and preservation) aren't 
>really tested by this benchmark.<

In practice most times real-world Java programs show a good enough performance 
even taking in account detection and preservation too.


>These are the timings without dynamic memory allocation:
>>>   D 1:   8.47 DMD [+ scope]
>>>   D 2:   7.41 DMD + scope
>>>   Java:  0.28 V.1.6.0_14, -server -XX:+DoEscapeAnalysis

It's not exactly the same, because in that Java code I have used a program-wide 
optimization flag (that I guess will become default), while in D I have had to 
add a "scope" everywhere, and I think adding "scope" is less safe than letting 
the compiler perform an escape analysis.

So I am tempted to put the 0.28 seconds result among the dynamic allocation 
timings, even if technically it is not, because for the programmer the program 
"feels" and looks and acts like a dynamic allocation, it's just faster :-) In 
the end what counts is how well the programs runs after the compiler has done 
its work.


>D's performance is unexpectedly bad, so much that I expect that it might be 
>using dynamic memory allocation anyway despite the 'scope' keyword. Java is 
>clever in that it eliminates unnecessary dynamic memory allocations 
>automatically.<

I think Java here is doing a bit more than just removing the dynamic 
allocation. I don't think D (compiled with LDC) is doing doing any allocation 
here. I'll ask to the LDC IRC channel.
I'll also take a look at the asm generated by the JavaVM (it's not handy to 
find the asm generated by the JVM, you need to install a debug version of it... 
how stupid).

-

Sam Hu:

>I am sorry to hear that,really,really sorry.<

Wait, things may not be that bad. And even if they are bad, the developers of 
the LDC compiler may find ways to improve the situation.

-

Robert Fraser:

>It suggests that for dynamic allocation of many small objects via "new", Java 
>is an order of magnitude faster than C++, which in turn is slightly faster 
>than D.<

Yes, for such tiny benchmarks I have seen several times 10-12 higher allocation 
performance in Java compared to D1-DMD. But real programs don't use all their 
time allocating and freeing memory...

Bye,
bearophile


Re: Garbage collection in D

2009-06-04 Thread Frits van Bommel

bearophile wrote:

Rainer Deyke:

D's performance is unexpectedly bad, so much that I expect that it might be using 
dynamic memory allocation anyway despite the 'scope' keyword. Java is clever in 
that it eliminates unnecessary dynamic memory allocations automatically.<


I think Java here is doing a bit more than just removing the dynamic 
allocation. I don't think D (compiled with LDC) is doing doing any allocation 
here. I'll ask to the LDC IRC channel.


LDC actually still does a dynamic allocation there because it doesn't eliminate 
dynamic allocations in loops.
This is unfortunate, but I haven't yet had the time to figure out how to get the 
optimization passes to prove the allocation can't be live when reached again. 
(If multiple instances of memory allocated at the same allocation site may be 
reachable at the same time, it's not safe to use a stack allocation instead of a 
heap allocation)


It's on my to-do list, though.


Re: Garbage collection in D

2009-06-04 Thread bearophile
Frits van Bommel:
> LDC actually still does a dynamic allocation there because it doesn't 
> eliminate 
> dynamic allocations in loops.

I have compiled the loop in foo() with LDC:

class AllocationItem {
int value;
this(int v) { this.value = v; }
}
int foo(int iters) {
int sum = 0;
for (int i = 0; i < iters; ++i) {
scope auto item = new AllocationItem(i);
sum += item.value;
}
return sum;
}

The asm of the core of the loop:

.LBB2_2:
movl$_D11gc_test2b_d14AllocationItem6__vtblZ, 8(%esp)
movl$0, 12(%esp)
movl%edi, 16(%esp)
movl%ebx, (%esp)
call_d_callfinalizer
incl%edi
cmpl%esi, %edi
jne .LBB2_2

I can see a call to finalizer, but not the allocation?


> This is unfortunate, but I haven't yet had the time to figure out how to get 
> the 
> optimization passes to prove the allocation can't be live when reached again. 
> (If multiple instances of memory allocated at the same allocation site may be 
> reachable at the same time, it's not safe to use a stack allocation instead 
> of a 
> heap allocation)

The new JavaVM with the option I have shown is clearly able to do such things.
Can't you take a look at the source code of the JavaVM? :-)
There's a huge amount of NIH in the open source :-)

Bye,
bearophile


Re: Garbage collection in D

2009-06-04 Thread Frits van Bommel

bearophile wrote:

Frits van Bommel:
LDC actually still does a dynamic allocation there because it doesn't eliminate 
dynamic allocations in loops.


I have compiled the loop in foo() with LDC:


[snip]

scope auto item = new AllocationItem(i);

[snip]


The asm of the core of the loop:

.LBB2_2:
movl$_D11gc_test2b_d14AllocationItem6__vtblZ, 8(%esp)
movl$0, 12(%esp)
movl%edi, 16(%esp)
movl%ebx, (%esp)
call_d_callfinalizer
incl%edi
cmpl%esi, %edi
jne .LBB2_2

I can see a call to finalizer, but not the allocation?


Sorry, I thought we were talking about the code without 'scope'. Of course the 
class is indeed stack-allocated if you use scope.


(The following:

This is unfortunate, but I haven't yet had the time to figure out how to get the 
optimization passes to prove the allocation can't be live when reached again. 
(If multiple instances of memory allocated at the same allocation site may be 
reachable at the same time, it's not safe to use a stack allocation instead of a 
heap allocation)


only applies when 'scope' was not used, and the compiler therefore initially 
heap-allocated it)



The new JavaVM with the option I have shown is clearly able to do such things.
Can't you take a look at the source code of the JavaVM? :-)
There's a huge amount of NIH in the open source :-)


I suspect the Java VM uses a different internal representation of the code than 
LLVM does...


Re: Garbage collection in D

2009-06-04 Thread Robert Fraser

bearophile wrote:

Yes, for such tiny benchmarks I have seen several times 10-12 higher allocation 
performance in Java compared to D1-DMD. But real programs don't use all their 
time allocating and freeing memory...

Bye,
bearophile


For the compiler I'm working on now (in D), I wanted to check the 
affects of allocation on performance. Using a placement new, the time 
for lex/parse/semantic/type-infer/codegen (on a really huge in-memory 
file) went from ~6 seconds to ~4 seconds (don't have the exact timings, 
and can't repro right now since I'm redoing inference). So I'd say that 
even in real-world applications, these things have an effect.


Of course, this only applies to programs which allocate and throw away a 
lot of small objects. This is a style encouraged by Java and C#'s 
programming models, much less so by, say, C++'s.


Re: Garbage collection in D

2009-06-04 Thread Robert Fraser

Frits van Bommel wrote:
The new JavaVM with the option I have shown is clearly able to do such 
things.

Can't you take a look at the source code of the JavaVM? :-)
There's a huge amount of NIH in the open source :-)


I suspect the Java VM uses a different internal representation of the 
code than LLVM does...


HotSpot uses 3-argument SSA for IR, AFAIK... I think LLVM is also 
SSA-based, right? But the Java source is _quite_ complex.


Re: Garbage collection in D

2009-06-04 Thread bearophile
Robert Fraser:
> Of course, this only applies to programs which allocate and throw away a 
> lot of small objects. This is a style encouraged by Java and C#'s 
> programming models, much less so by, say, C++'s.

Right, there are many potential new D programmers coming from Java that may 
want to use that style that relies a lot on an efficient GC. But you are 
missing another important style of programming that allocates & frees tons of 
objects: functional-style programming, where immutable data is the norm. If the 
D2 language will want to appeal to functional programmers it will have to 
manage such immutables more efficiently.

Bye,
bearophile


Re: Garbage collection in D

2009-06-10 Thread bearophile
LDC is a moving target because it's actively developed, and generally things 
improve with time.
This is a recent change by the quite active Frits van Bommel:
http://www.dsource.org/projects/ldc/changeset/1486%3A9ed0695cb93c

This is a cleaned up version discussed in this thread:

import tango.stdc.stdio: printf;
import Integer = tango.text.convert.Integer;

class AllocationItem {
int value;
this(int v) { this.value = v; }
}

int foo(int iters) {
int sum = 0;
for (int i = 0; i < iters; ++i) {
auto item = new AllocationItem(i);
sum += item.value;
}
return sum;
}

void main(char[][] args) {
int iters = Integer.parse(args[1]);
printf("%d\n", foo(iters));
}


The asm generated by the last LDC (based on DMD v1.045 and llvm 2.6svn (Tue Jun 
 9 22:34:25 2009)) (this is just the important part of the asm):

foo:
testl   %eax, %eax
jle .LBB2_4
movl%eax, %ecx
xorl%eax, %eax
.align  16
.LBB2_2:
incl%eax
cmpl%ecx, %eax
jne .LBB2_2
leal-2(%ecx), %eax
leal-1(%ecx), %edx
mull%edx
shldl   $31, %eax, %edx
leal-1(%edx,%ecx), %eax
ret
.LBB2_4:
xorl%eax, %eax
ret
*/


This is the same code with "scope" added:

import tango.stdc.stdio: printf;
import Integer = tango.text.convert.Integer;

class AllocationItem {
int value;
this(int v) { this.value = v; }
}

int foo(int iters) {
int sum = 0;
for (int i = 0; i < iters; ++i) {
scope auto item = new AllocationItem(i);
sum += item.value;
}
return sum;
}

void main(char[][] args) {
int iters = Integer.parse(args[1]);
printf("%d\n", foo(iters));
}

Its asm:

/*
foo:
pushl   %ebx
pushl   %edi
pushl   %esi
subl$24, %esp
testl   %eax, %eax
jle .LBB2_4
movl%eax, %esi
xorl%edi, %edi
leal8(%esp), %ebx
.align  16
.LBB2_2:
movl$_D11gc_test2b_d14AllocationItem6__vtblZ, 8(%esp)
movl$0, 12(%esp)
movl%edi, 16(%esp)
movl%ebx, (%esp)
call_d_callfinalizer
incl%edi
cmpl%esi, %edi
jne .LBB2_2
leal-2(%esi), %eax
leal-1(%esi), %ecx
mull%ecx
shldl   $31, %eax, %edx
leal-1(%edx,%esi), %eax
jmp .LBB2_5
.LBB2_4:
xorl%eax, %eax
.LBB2_5:
addl$24, %esp
popl%esi
popl%edi
popl%ebx
ret
*/


The running time:
...$ elaps ./gc_test1 25000
-1782069568
real0m0.170s
user0m0.160s
sys 0m0.010s

The version with "scope":
...$ elaps ./gc_test2 25000
-1782069568
real0m6.430s
user0m6.430s
sys 0m0.000s

(Later I may try again with a less simple and more realistic benchmark, because 
this is too much a toy to be interesting.)

Bye,
bearophile


Re: Garbage collection in D

2009-07-25 Thread Aelx
Diwaker Gupta Wrote:

> I've just started to play around with D, and I'm hoping someone can clarify 
> this. I wrote a very simple program that just allocates lots of objects, in 
> order to benchmark the garbage collector in D. For comparison, I wrote the 
> programs in C++, Java and D:
> C++: http://gist.github.com/122708
> Java: http://gist.github.com/122709
> D: http://gist.github.com/121790
> 
> With an iteration count of , I get the following numbers:
> JAVA:
> 0:01.60 elapsed, 1.25 user, 0.28 system
> C++:
> 0:04.99 elapsed, 4.97 user, 0.00 system
> D:
> 0:25.28 elapsed, 25.22 user, 0.00 system
> 
> As you can see, D is abysmally slow compared to C++ and Java. This is using 
> the GNU gdc compiler. I'm hoping the community can give me some insight on 
> what is going on.
> 
> Thanks,
> Diwaker

Hi.
Inspired by this idea I changed somehow rules to make it more complicated task. 
So they are:
1. every "AllocationItem" has references to three other items. 
2. generate "n_items" in static array "items" of type "AllocationItem"
with "value" field set to "0"
3. make random connections between all this items by their reference fields
4. iterate "n_iters" times with the following agorithm 
 a) create new "AllocationArray" with "value" set to "1"
 b) replace random item from the array "items" with this new item
 c) add connections to this item
 d) remove (variant 1) or change (variant 2) three random connections
 e) now if some object isn't referenced by others it should be removed (GC 
collected).
5. calculate count  of old items (with "value" set to 0) and new ones
Here are my programs in D and Java. There is no C++ variant, sorry.
In D I used modified for D2 Bill Baxter's weak reference module: 
http://www.dsource.org/projects/scrapple/browser/trunk/weakref

now results:
1) it works strange, as from time to time it gives different results in D2 
(approx. 1 in 10) and it's no by RNG.
2) java's version is awfully slow (may be because it's my second java app, 
first was 8 jears ago). now I hate java even more.
3) java and D give different results. It's all strange. Maybe I made something 
wrong.



Re: Garbage collection in D

2009-07-25 Thread Aelx
Oh my. I forgot programs, here they are:
http://gist.github.com/154958



pointers, assignments, Garbage Collection Oh My?

2013-07-10 Thread JohnnyK
I hope you like the subject matter and I hope it is not too 
simplistic or have been answered before.
  Anyway I have a question about how the garbage collector works 
in a very specific situation.  When passing string type to a 
function in a shared library or DLL and assigning it to a 
variable of type string inside the function and returning the 
internal string.  Such as this.


export string mytest(string tstStr)
{
  string st = tstStr;
  /* abbreviated to protect the innocent but other operations
 such as concatenating and deleting may be done to st before 
the return

  */
  return st;
}

Is the string type a pointer or is it something else?  In the 
line where tstStr is assigned to st does it copy the address in 
tstStr to st or does it copy the value in tstStr?  I am just a 
bit confused about string types since I come from a C background 
and C has no type like this.  Also what is returned by this 
function?  Does this function return a pointer or the contents of 
an array?  If I do export this what does it do to the Garbage 
Collection?  Does the Garbage Collection collect tstStr or st?  
Also notice the comment in the function.




Temporarily protect array from garbage collection

2014-04-24 Thread Lars T. Kyllingstad via Digitalmars-d-learn
Is it possible to temporarily prevent the garbage collector from 
collecting a memory block even if there are no references to it?


The use case is as follows:  I want to call a C library function 
which expects to take ownership of a buffer.  It looks something 
like this:


alias FreeFunc = extern(C) void function(void*, void*) 
nothrow;


extern(C) void foo(void* buf, size_t len,
   FreeFunc free, void* ctx) nothrow;

Here, 'buf' is a pointer to the buffer, 'len' is the length of 
the buffer, 'free' is a function to deallocate the buffer when 
the library is done with it, and 'ctx' is a user-supplied context 
pointer.  Upon deallocation, 'free' receives two parameters; the 
pointer to the buffer and the context pointer.  The latter can be 
anything, even null, as it is just passed to 'free' and not used 
for anything else.


Here is the problem:  I want to be able to use a 
garbage-collected dynamic array with this function, but I don't 
want to have to retain a reference to it in my program.  (I don't 
know when the C library will call the free function.)  In other 
words, I want something like this:


extern(C) void myFree(void* ptr, void* ctx)
{
enableGCFor(ptr);
}

auto arr = new int[123];
disableGCFor(arr);
foo(arr.ptr, arr.length, &myFree, null);
arr = null;

Is this at all possible?

Thanks,
Lars


reference to delegates and garbage collection

2014-07-14 Thread AnFive via Digitalmars-d-learn

Hello everybody. I am new to D, and I am trying to familiarize
with all the new (to me) features.
I have a question about a strange behavior I cannot understand.
(In case it matters, I am using gdc 2.065 for Windows, but the
same happens with dmd).

Example code :

class A {   
void delegate() del;

~this() { writeln("A Destructor called"); }   
}

class B {   
void fun() {}   
}

A makeA() { 
auto a = new A();
a.del = &(new B().fun);
return a;
}

void main() {

auto a = makeA();
 /* Magic line goes here, see below */
a = null;

foreach(i; 0..10) {
writeln("Collecting");
GC.collect();   
}

writeln("End");   
}

If I run this code, the instance of A is of course collected at
the first call to GC.collect().
But if I call the delegate (i.e. a.del() ) in the "magic line",
the instance is not destroyed until the end of the main. If I
"wrap" the call to a.del() in another function or method, the
instance is collected.

Can somebody explain why this happens? Is it just a strangeness
of the GC? Does calling the delegate keep a reference to a in the
current scope? Am I going crazy? I spent about half an hour
looking for a non-existent memory leak in my program because of
this behavior, so I'd like to have an explanation.

Thanks in advance!


Re: Freeing of memory (garbage collection)

2008-12-08 Thread BCS

Reply to Dan,


A couple of questions:

1: Even though D has an automatic garbage collector, is one still
allowed to free the memory of a malloced array manually (using free ()
), to avoid pauses in the program?



Yes, in fact if you malloc memory you MUST free it. Only stuff like dynamic 
arrays, AAs and new'ed stuff gets cleaned up by the GC.



2: One justification on the website for using automatic garbage
collection is how "allocated memory will only be freed if system RAM
is tight". But surely that's silly, since one may want *lots* of
memory free for a completely different application (merely memory
being 'tight' before freeing may not be good enough - one may want D
to free memory sooner).



With virtual memory and swap space, this (almost) no longer matters. If you 
aren't using memory sooner or later it's not using your RAM but just sitting 
on the disk.





Re: Freeing of memory (garbage collection)

2008-12-09 Thread bearophile
Dan W:
> 1: Even though D has an automatic garbage collector, is one still
> allowed to free the memory of a malloced array manually (using free
> () ), to avoid pauses in the program?

Other people here will just answer your question. But remember that in D manual 
memory management is done only in special situations, most code of most 
programs just use the GC.

Bye,
bearophile


Re: Freeing of memory (garbage collection)

2008-12-09 Thread Daniel White
Thanks for that reply. I wonder if extending automatic garbage
collection for malloced memory would be a good idea...

> Only stuff like dynamic 
> arrays, AAs and new'ed stuff gets cleaned up by the GC.

For the above types of allocating memory, is there a way to 'lock' a
variable and say to D, "don't free this memory until I allow you to",
and also for it to allow you to free it manually when/if need be?


Re: Freeing of memory (garbage collection)

2008-12-09 Thread Steven Schveighoffer
"Daniel White" wrote
> Thanks for that reply. I wonder if extending automatic garbage
> collection for malloced memory would be a good idea...
>
>> Only stuff like dynamic
>> arrays, AAs and new'ed stuff gets cleaned up by the GC.
>
> For the above types of allocating memory, is there a way to 'lock' a
> variable and say to D, "don't free this memory until I allow you to",
> and also for it to allow you to free it manually when/if need be?

One thing you can do, that nobody has mentioned yet, is delete memory that 
you have allocated using the GC.

Deleting a block of memory that the GC has allocated allows you to reuse 
that memory without going through a full GC collect cycle, and so most 
likely your performance will be better.  Using delete in key spots can be 
good.

But using manual memory mangement prevents lots of good designs, so use with 
caution.

Lastly, if you are allocating lots of temporary classes, try declaring them 
as scope.  This allocates the class on the stack if possible.  Note that any 
memory allocated by the constructor will still go through the GC.  Also note 
that you can't use a scoped class once its scope is finished.  e.g.:
class C
{ ... }

...

while(x > 0)
{
   scope c = new C(x--); // c is allocated on the stack.  scope keyword 
implies the type.
   c.doSomething();
   // c is deleted from stack at end of loop iteration.  No heap activity.
}

-Steve 




Re: Freeing of memory (garbage collection)

2008-12-09 Thread Jarrett Billingsley
On Tue, Dec 9, 2008 at 9:16 AM, Daniel White <[EMAIL PROTECTED]> wrote:
> Thanks for that reply. I wonder if extending automatic garbage
> collection for malloced memory would be a good idea...

That would be a bad idea.  Then how would you do manual memory
management in the few cases that absolutely require it?

>> Only stuff like dynamic
>> arrays, AAs and new'ed stuff gets cleaned up by the GC.
>
> For the above types of allocating memory, is there a way to 'lock' a
> variable and say to D, "don't free this memory until I allow you to",
> and also for it to allow you to free it manually when/if need be?

Yes, you can use std.gc.addRoot in Phobos (in D1), and GC.addRoot if
you're using Tango (import tango.core.Memory) or D2 (import
core.memory).


Re: Freeing of memory (garbage collection)

2008-12-09 Thread Jarrett Billingsley
On Tue, Dec 9, 2008 at 9:42 AM, Jarrett Billingsley
<[EMAIL PROTECTED]> wrote:
> On Tue, Dec 9, 2008 at 9:16 AM, Daniel White <[EMAIL PROTECTED]> wrote:
>> Thanks for that reply. I wonder if extending automatic garbage
>> collection for malloced memory would be a good idea...
>
> That would be a bad idea.  Then how would you do manual memory
> management in the few cases that absolutely require it?
>
>>> Only stuff like dynamic
>>> arrays, AAs and new'ed stuff gets cleaned up by the GC.
>>
>> For the above types of allocating memory, is there a way to 'lock' a
>> variable and say to D, "don't free this memory until I allow you to",
>> and also for it to allow you to free it manually when/if need be?
>
> Yes, you can use std.gc.addRoot in Phobos (in D1), and GC.addRoot if
> you're using Tango (import tango.core.Memory) or D2 (import
> core.memory).

Oh yeah, and you can use 'delete' on arrays, classes, and structs
allocated on the heap, but oddly not with AAs.


Re: Freeing of memory (garbage collection)

2008-12-09 Thread Daniel White
> That would be a bad idea.  Then how would you do manual memory
> management in the few cases that absolutely require it?

Two ways. Either:

a: being able to lock the variable so that the garbage collector
can't touch it until you unlock it.

b: Using a slightly different version of malloc (say 'mallocl') which again,
makes it shielded against the garbage collector's wrath.


Re: Freeing of memory (garbage collection)

2008-12-09 Thread Jarrett Billingsley
On Tue, Dec 9, 2008 at 11:08 AM, Daniel White <[EMAIL PROTECTED]> wrote:
>> That would be a bad idea.  Then how would you do manual memory
>> management in the few cases that absolutely require it?
>
> Two ways. Either:
>
> a: being able to lock the variable so that the garbage collector
> can't touch it until you unlock it.

Why not just use GC-allocated memory and use addRoot then?

> b: Using a slightly different version of malloc (say 'mallocl') which again,
> makes it shielded against the garbage collector's wrath.

At which point you're back to the same situation as we have currently.


Re: Freeing of memory (garbage collection)

2008-12-09 Thread Daniel White
Jarrett Billingsley Wrote:

> On Tue, Dec 9, 2008 at 11:08 AM, Daniel White <[EMAIL PROTECTED]> wrote:
> >> That would be a bad idea.  Then how would you do manual memory
> >> management in the few cases that absolutely require it?
> >
> > Two ways. Either:
> >
> > a: being able to lock the variable so that the garbage collector
> > can't touch it until you unlock it.
> 
> Why not just use GC-allocated memory and use addRoot then?

Well that question points at the deeper issue of why bother having malloc at 
all.


Re: Freeing of memory (garbage collection)

2008-12-09 Thread Jarrett Billingsley
On Tue, Dec 9, 2008 at 2:53 PM, Daniel White <[EMAIL PROTECTED]> wrote:
> Jarrett Billingsley Wrote:
>
>> On Tue, Dec 9, 2008 at 11:08 AM, Daniel White <[EMAIL PROTECTED]> wrote:
>> >> That would be a bad idea.  Then how would you do manual memory
>> >> management in the few cases that absolutely require it?
>> >
>> > Two ways. Either:
>> >
>> > a: being able to lock the variable so that the garbage collector
>> > can't touch it until you unlock it.
>>
>> Why not just use GC-allocated memory and use addRoot then?
>
> Well that question points at the deeper issue of why bother having malloc at 
> all.

For interaction with some C libraries.  Or for implementing your own
memory management without having to deal with the GC.


Re: Freeing of memory (garbage collection)

2008-12-09 Thread Christopher Wright

Daniel White wrote:

That would be a bad idea.  Then how would you do manual memory
management in the few cases that absolutely require it?


Two ways. Either:

a: being able to lock the variable so that the garbage collector
can't touch it until you unlock it.


If you have a reference to the memory, the GC won't collect it. Unless 
you make a habit of hiding pointers inside non-pointer types, that is, 
which can result in undefined behavior if the hidden pointer points to 
GC-allocated memory.


If you don't have any reference to that memory, then the garbage 
collector can free it, but in that case, I don't see why it would be an 
issue, most of the time. If you have a destructor, just be careful -- 
for instance, if you have an open file in that object and its destructor 
closes that file.



b: Using a slightly different version of malloc (say 'mallocl') which again,
makes it shielded against the garbage collector's wrath.


malloc is C stdlib malloc. The garbage collector won't touch it.


Re: Freeing of memory (garbage collection)

2008-12-09 Thread bearophile
Steven Schveighoffer:
> One thing you can do, that nobody has mentioned yet, is delete memory that 
> you have allocated using the GC.

Leaving the GC manage and free your memory is usually OK. Managing manually 
your memory allocated from the C heap is doable. But freeing manually and 
forcefully memory allocated by the GC seems dangerous to me.

Bye,
bearophile


Re: Freeing of memory (garbage collection)

2008-12-13 Thread Sergey Gromov
Tue, 9 Dec 2008 03:25:07 + (UTC), Dan W wrote:

> 1: Even though D has an automatic garbage collector, is one still
> allowed to free the memory of a malloced array manually (using free
> () ), to avoid pauses in the program?

Just to clarify.  There are 3 types of allocation:

1.  std.c.stdlib.malloc().  The good ol' plain C allocation which is
entirely manual and requires std.c.stdlib.free() to free memory.

2.  std.gc.malloc(), or tango.core.Memory.GC.malloc(), or
core.memory.GC.malloc() in recent D2.  These allocate an uninitialized
but GC-managed and GC-scanned by default memory.  That is, this memory
gets automatically freed as soon as there are no GC-managed references
to it.  You can explicitly free this memory using the delete keyword.
You can direct GC not to scan this memory for pointers using
std.gc.hasNoPointers() or equivalent.

3.  Memory allocated via new, arrays, etc.  This memory is GC-managed
but can be freed explicitly using the delete keyword.

> 2: One justification on the website for using automatic garbage
> collection is how "allocated memory will only be freed if system RAM
> is tight". But surely that's silly, since one may want *lots* of
> memory free for a completely different application (merely memory
> being 'tight' before freeing may not be good enough - one may want D
> to free memory sooner).

I don't think this is a valid justification.  One of the main GC
justifications is an ability to implement flexible data models where
data owner is uncertain or unknown.  In such cases GC makes it easy to
avoid data duplication.


Re: Garbage Collection, Allocators/Deallocators and

2010-09-18 Thread Sean Kelly
Ivo Kasiuk Wrote:

> Hi,
> 
> to improve my understanding of the GC and when/how
> allocators/deallocators and constructors/destructors get called, I wrote
> a little test program. And now I understand even less than before...
...
> Running this with DMD 2.049, I observed the following:
> 
> - S1(int), S2(int), C1(), C2(), S1.new and S2.new get invoked in every
> cycle of the loop, as you would expect.
> 
> - ~C2() also gets invoked frequently.
> 
> - ~S1(), ~S2(), ~C1(), S1.delete and C1.delete never ever get called.
> 
> - The program does not run out of memory and actually has a relatively
> modest memory footprint, so it does not seem to leak memory. (When using
> std.c.stdlib.malloc instead of GC.malloc it runs out of memory almost
> immediately).
> 
> It is good to see that the GC apparently really frees the unreferenced
> memory again. However, I don't understand why the deallocators and the
> destructors (apart from ~C2) do not get called. If the memory for the
> objects gets freed, as is apparently the case, then why are there no
> destructor and deallocator calls for these objects?

The deallocator is only called if you delete the object, not when it's 
finalized by the GC.  The GC will only finalize something that is in its memory 
space, so if this happens there's no need to call the deallocator.


Re: Garbage Collection, Allocators/Deallocators and

2010-09-18 Thread Ivo Kasiuk
Am Samstag, den 18.09.2010, 10:08 -0400 schrieb Sean Kelly:
> Ivo Kasiuk Wrote:
> 
> > Hi,
> > 
> > to improve my understanding of the GC and when/how
> > allocators/deallocators and constructors/destructors get called, I wrote
> > a little test program. And now I understand even less than before...
> ...
> > Running this with DMD 2.049, I observed the following:
> > 
> > - S1(int), S2(int), C1(), C2(), S1.new and S2.new get invoked in every
> > cycle of the loop, as you would expect.
> > 
> > - ~C2() also gets invoked frequently.
> > 
> > - ~S1(), ~S2(), ~C1(), S1.delete and C1.delete never ever get called.
> > 
> > - The program does not run out of memory and actually has a relatively
> > modest memory footprint, so it does not seem to leak memory. (When using
> > std.c.stdlib.malloc instead of GC.malloc it runs out of memory almost
> > immediately).
> > 
> > It is good to see that the GC apparently really frees the unreferenced
> > memory again. However, I don't understand why the deallocators and the
> > destructors (apart from ~C2) do not get called. If the memory for the
> > objects gets freed, as is apparently the case, then why are there no
> > destructor and deallocator calls for these objects?
> 
> The deallocator is only called if you delete the object, not when it's 
> finalized by the GC.  The GC will only finalize something that is in its 
> memory space, so if this happens there's no need to call the deallocator.

Ok, that makes sense. So the deallocators really should not get called
in this case. But why are the destructors not invoked when the GC
finalizes the objects?

Exploring the example a bit further:
If C's malloc is used instead of GC.malloc then the deallocators also
are not called and the program runs out of memory. How are the objects
supposed to get finalized in this case - do I have to use the delete
keyword explicitly?

An interesting case is when using C's malloc for C1 and using the scope
attribute for c1:

class C1 {
  ubyte[1_000_000] buf;
  new(size_t size) {
void* ptr = std.c.stdlib.malloc(size);
if (ptr is null)
  throw new OutOfMemoryError(__FILE__, __LINE__);
writefln("C1.new(%d) = %x", size, ptr);
   return ptr;
  }
  delete(void* ptr) {
writefln("C1.delete %x", ptr);
if (ptr) std.c.stdlib.free(ptr);
  }
  this() { writeln("C1()"); }
  ~this() { writeln("~C1()"); }
}
...
  scope C1 c1 = new C1;

In this case, ~C1 gets invoked but not C1.delete. Nevertheless, the
memory appears to get freed (normal memory consumption, no OutOfMemory).
How does this happen?




Re: Garbage Collection, Allocators/Deallocators and

2010-09-18 Thread Ivo Kasiuk
> An interesting case is when using C's malloc for C1 and using the scope
> attribute for c1:
> 
> class C1 {
>   ubyte[1_000_000] buf;
>   new(size_t size) {
> void* ptr = std.c.stdlib.malloc(size);
> if (ptr is null)
>   throw new OutOfMemoryError(__FILE__, __LINE__);
> writefln("C1.new(%d) = %x", size, ptr);
>return ptr;
>   }
>   delete(void* ptr) {
> writefln("C1.delete %x", ptr);
> if (ptr) std.c.stdlib.free(ptr);
>   }
>   this() { writeln("C1()"); }
>   ~this() { writeln("~C1()"); }
> }
> ...
>   scope C1 c1 = new C1;
> 
> In this case, ~C1 gets invoked but not C1.delete. Nevertheless, the
> memory appears to get freed (normal memory consumption, no OutOfMemory).
> How does this happen?

Ok, I figured that out myself: c1 is allocated on the stack in this
case, so no neither the allocator nor the deallocator need to get
called.



Re: Garbage Collection, Allocators/Deallocators and

2010-09-18 Thread Simen kjaeraas

Ivo Kasiuk  wrote:


Ok, that makes sense. So the deallocators really should not get called
in this case. But why are the destructors not invoked when the GC
finalizes the objects?


For S1 and S2, this is a known bug - destructors of structs on the heap
don't get called.

As for C1, I have no idea what's happening. Definitely a bug, though.



Exploring the example a bit further:
If C's malloc is used instead of GC.malloc then the deallocators also
are not called and the program runs out of memory. How are the objects
supposed to get finalized in this case - do I have to use the delete
keyword explicitly?


If you use C's malloc, you will also have to use C's free.

--
Simen


Re: Garbage Collection, Allocators/Deallocators and

2010-09-18 Thread Ivo Kasiuk
> > Exploring the example a bit further:
> > If C's malloc is used instead of GC.malloc then the deallocators also
> > are not called and the program runs out of memory. How are the objects
> > supposed to get finalized in this case - do I have to use the delete
> > keyword explicitly?
> 
> If you use C's malloc, you will also have to use C's free.

Yes, obviously. But the deallocator which contains the call to C's free
has to be invoked by someone, otherwise it's useless. So that is my
question: how should finalization and deallocation get triggered in this
scenario (where non-GC memory is used)?



Re: Garbage Collection, Allocators/Deallocators and

2010-09-18 Thread Simen kjaeraas

Ivo Kasiuk  wrote:


> Exploring the example a bit further:
> If C's malloc is used instead of GC.malloc then the deallocators also
> are not called and the program runs out of memory. How are the objects
> supposed to get finalized in this case - do I have to use the delete
> keyword explicitly?

If you use C's malloc, you will also have to use C's free.


Yes, obviously. But the deallocator which contains the call to C's free
has to be invoked by someone, otherwise it's useless. So that is my
question: how should finalization and deallocation get triggered in this
scenario (where non-GC memory is used)?


delete will, as long as it is kept in D, call the deallocator method.
Unless the allocated memory is not registered with the garbage collector,
it will be ignored by the garbage collector, and you will have to manually
delete allocated objects. The point of using C's malloc and free is
exactly that - the GC will ignore your objects, and you are free to (that
is, have to) manage their lifetimes yourself.

--
Simen


Re: Garbage Collection, Allocators/Deallocators and

2010-09-19 Thread Ivo Kasiuk

> >> > Exploring the example a bit further:
> >> > If C's malloc is used instead of GC.malloc then the deallocators also
> >> > are not called and the program runs out of memory. How are the objects
> >> > supposed to get finalized in this case - do I have to use the delete
> >> > keyword explicitly?
> >>
> >> If you use C's malloc, you will also have to use C's free.
> >
> > Yes, obviously. But the deallocator which contains the call to C's free
> > has to be invoked by someone, otherwise it's useless. So that is my
> > question: how should finalization and deallocation get triggered in this
> > scenario (where non-GC memory is used)?
> 
> delete will, as long as it is kept in D, call the deallocator method.
> Unless the allocated memory is not registered with the garbage collector,
> it will be ignored by the garbage collector, and you will have to manually
> delete allocated objects. The point of using C's malloc and free is
> exactly that - the GC will ignore your objects, and you are free to (that
> is, have to) manage their lifetimes yourself.
> 

Thanks for the explanation.
Summing up what I have learned now:
- When GC-allocated memory is used the deallocator is not called when
the GC automatically finalizes the object, but only when the delete
keyword is used explicitly.
- When non-GC memory is used the deallocator is also only called when
the delete keyword is used, and deallocation/finalization is never
triggered automatically.

In other words: the deallocator only ever gets called when the delete
keyword is used. What does this mean if the delete keyword is not kept
in D:
- Will deallocators also be obsolete then?
- Is there any way the regular finalization sequence (i.e. including
automatic invoking of the destructors) can be run for an object that
uses non-GC memory?




Re: Garbage Collection, Allocators/Deallocators and

2010-09-19 Thread Ivo Kasiuk
> > Ok, that makes sense. So the deallocators really should not get called
> > in this case. But why are the destructors not invoked when the GC
> > finalizes the objects?
> 
> For S1 and S2, this is a known bug - destructors of structs on the heap
> don't get called.

Ah, I see. You mean #2834. That explains it, thanks.

> As for C1, I have no idea what's happening. Definitely a bug, though.

I am not sure that it is a bug that ~C1 (and also ~S1) is not invoked.
After all, we called GC.malloc manually. So the GC knows about the
memory region but is possibly not aware that it contains the object. If
this is true it would be logical that the memory is freed but the
destructor is not called.




  1   2   >