Thread overview | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
April 02, 2014 When this will be freed? | ||||
---|---|---|---|---|
| ||||
auto example(char* test) { return toStringz(to!string(test) ~ " world!"); } When that return string will be freed? What about: extern(C) auto example(....) ? |
April 02, 2014 Re: When this will be freed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrea Fontana | On 2014-04-02 17:45, Andrea Fontana wrote: > auto example(char* test) { return toStringz(to!string(test) ~ " world!"); } > > When that return string will be freed? When there is no reference left to the string, the garbage collector is free to collect it when it chooses to. > What about: > > extern(C) auto example(....) Same as above, extern(C) does not change how memory is collected. If it is a C function, then it depends entirely on that particular function. -- /Jacob Carlborg |
April 02, 2014 Re: When this will be freed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrea Fontana | On Wednesday, 2 April 2014 at 15:45:06 UTC, Andrea Fontana wrote:
>
> auto example(char* test) { return toStringz(to!string(test) ~ " world!"); }
>
> When that return string will be freed?
>
> What about:
>
> extern(C) auto example(....)
>
> ?
to!string allocates on the GC heap when given a char* (it has to, in order to safely produce immutable data in the string).
It will be freed by the first garbage collection ocurring after all references to that memory are dead.
|
April 02, 2014 Re: When this will be freed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Wednesday, 2 April 2014 at 15:53:52 UTC, Jacob Carlborg wrote: > On 2014-04-02 17:45, Andrea Fontana wrote: > >> auto example(char* test) { return toStringz(to!string(test) ~ " world!"); } >> >> When that return string will be freed? > > When there is no reference left to the string, the garbage collector is free to collect it when it chooses to. > That's expected. >> What about: >> >> extern(C) auto example(....) > > Same as above, extern(C) does not change how memory is collected. If it is a C function, then it depends entirely on that particular function. I mean: if it is an exported function (of a shared library) what happens? There's no reference kept anywhere (in D). So if I'm right it could be freed immediatly by GC. Right? |
April 02, 2014 Re: When this will be freed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrea Fontana | Am 02.04.2014 17:57, schrieb Andrea Fontana:
> On Wednesday, 2 April 2014 at 15:53:52 UTC, Jacob Carlborg wrote:
>> On 2014-04-02 17:45, Andrea Fontana wrote:
>>
>>> auto example(char* test) { return toStringz(to!string(test) ~ "
>>> world!"); }
>>>
>>> When that return string will be freed?
>>
>> When there is no reference left to the string, the garbage collector
>> is free to collect it when it chooses to.
>>
>
> That's expected.
>
>>> What about:
>>>
>>> extern(C) auto example(....)
>>
>> Same as above, extern(C) does not change how memory is collected. If
>> it is a C function, then it depends entirely on that particular function.
>
> I mean: if it is an exported function (of a shared library) what
> happens? There's no reference kept anywhere (in D). So if I'm right it
> could be freed immediatly by GC. Right?
>
If you pass that string to a C function, there is a reference on the stack. So this string will not be freed until that C-function returns. If that C-Function returns, it is very likely however that this was the only reference and the string will be freed the next time the garbage collector runs.
Kind Regards
Benjamin Thaut
|
April 04, 2014 Re: When this will be freed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benjamin Thaut | On Wednesday, 2 April 2014 at 16:51:57 UTC, Benjamin Thaut wrote: > Am 02.04.2014 17:57, schrieb Andrea Fontana: >> I mean: if it is an exported function (of a shared library) what >> happens? There's no reference kept anywhere (in D). So if I'm right it >> could be freed immediatly by GC. Right? >> > > If you pass that string to a C function, there is a reference on the stack. So this string will not be freed until that C-function returns. If that C-Function returns, it is very likely however that this was the only reference and the string will be freed the next time the garbage collector runs. This is unfortunately only true on x86 32-bit. For x86_64, the calling conventions (MS, SysV [1]) say that the first few parameters are passed in registers, and the same is probably true for other architectures. Usually this is still safe, as the pointer will normally either stay in its register, or will be spilled to the stack and kept there as long as the function still needs to use it. But one might imagine a corner case where it temporarily stores the pointer in a global or static variable. Even if the pointer will not be kept by the C function longer than the call, in such cases you would need to keep an additional reference where the GC can see it. [1] https://en.wikipedia.org/wiki/X86_calling_conventions#x86-64_calling_conventions |
April 04, 2014 Re: When this will be freed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On Fri, 04 Apr 2014 09:25:49 -0400, Marc Schütz <schuetzm@gmx.net> wrote:
> On Wednesday, 2 April 2014 at 16:51:57 UTC, Benjamin Thaut wrote:
>> Am 02.04.2014 17:57, schrieb Andrea Fontana:
>>> I mean: if it is an exported function (of a shared library) what
>>> happens? There's no reference kept anywhere (in D). So if I'm right it
>>> could be freed immediatly by GC. Right?
>>>
>>
>> If you pass that string to a C function, there is a reference on the stack. So this string will not be freed until that C-function returns. If that C-Function returns, it is very likely however that this was the only reference and the string will be freed the next time the garbage collector runs.
>
> This is unfortunately only true on x86 32-bit. For x86_64, the calling conventions (MS, SysV [1]) say that the first few parameters are passed in registers, and the same is probably true for other architectures.
>
> Usually this is still safe, as the pointer will normally either stay in its register, or will be spilled to the stack and kept there as long as the function still needs to use it. But one might imagine a corner case where it temporarily stores the pointer in a global or static variable. Even if the pointer will not be kept by the C function longer than the call, in such cases you would need to keep an additional reference where the GC can see it.
In cases where it is stored in global data, and that becomes the only reference, or if a C heap allocation is made, and the pointer is stored in there (perhaps to pass to another C function?), then it's quite possible the data could be collected prematurely in another thread.
You bring up a good point. This is something that should be considered when calling extern(C) functions.
-Steve
|
April 05, 2014 Re: When this will be freed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On 2014-04-04 15:25, "Marc Schütz" <schuetzm@gmx.net>" wrote: > This is unfortunately only true on x86 32-bit. For x86_64, the calling > conventions (MS, SysV [1]) say that the first few parameters are passed > in registers, and the same is probably true for other architectures. I'm not so familiar with calling conventions and how the stack and registers work. But take this as an example: extern (C) void foo (in char*); void bar () { string s = "asd"; foo(s.ptr); } Even if "s" is passed in a register to "foo", won't the stack of "bar" still be available until "foo" returns? -- /Jacob Carlborg |
April 05, 2014 Re: When this will be freed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Saturday, 5 April 2014 at 11:28:36 UTC, Jacob Carlborg wrote:
> On 2014-04-04 15:25, "Marc Schütz" <schuetzm@gmx.net>" wrote:
>
>> This is unfortunately only true on x86 32-bit. For x86_64, the calling
>> conventions (MS, SysV [1]) say that the first few parameters are passed
>> in registers, and the same is probably true for other architectures.
>
> I'm not so familiar with calling conventions and how the stack and registers work. But take this as an example:
>
> extern (C) void foo (in char*);
>
> void bar ()
> {
> string s = "asd";
> foo(s.ptr);
> }
>
> Even if "s" is passed in a register to "foo", won't the stack of "bar" still be available until "foo" returns?
Yes, but it doesn't necessarily contain `s` anymore. Today's compilers are intelligent enough to see that `s` is never used after the function call, and therefore don't even allocate a stack slot for it.
`foo` could be implemented like this (it's a C function, so `in` boils down to `const` without `scope`):
char *b;
void foo (const char *a) {
b = a;
// do something complex that causes all the registers to be reused
// => the only reference to the string is now in b, outside of the GC's view
// --> GC collects here <--
printf(b); // the string may have been collected here
}
|
April 05, 2014 Re: When this will be freed? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marc Schütz | On 2014-04-05 15:08, "Marc Schütz" <schuetzm@gmx.net>" wrote: > Yes, but it doesn't necessarily contain `s` anymore. Today's compilers > are intelligent enough to see that `s` is never used after the function > call, and therefore don't even allocate a stack slot for it. Ok, I see. > `foo` could be implemented like this (it's a C function, so `in` boils > down to `const` without `scope`): > > char *b; > void foo (const char *a) { > b = a; > // do something complex that causes all the registers to be reused > // => the only reference to the string is now in b, outside of the > GC's view > // --> GC collects here <-- > printf(b); // the string may have been collected here > } Of course, if the C function is storing the parameter in a global variable you got problems. You really need to be sure of what the C functions is doing. To be on the safe side there's always GC.addRoot. -- /Jacob Carlborg |
Copyright © 1999-2021 by the D Language Foundation