June 27, 2017 Advice wanted on garbage collection of sockets for c++ programmer using D | ||||
---|---|---|---|---|
| ||||
I'm coming from a C++ background so I'm not too used to garbage collection and it's implications. I have a function that creates a std.socket.Socket using new and connects to a tcp server, and writes some stuff to it. I then explicitly close the socket, and the socket object goes out of scope. I assume that I do need to explicitly call close on the socket as there is no deterministic destructor for class objects. I further assume that the runtime will garbage collect any memory allocated to the socket object at a later time. Am I doing this right with GC? In C++ I'd ensure that the Socket class had a destructor that closed the socket and I'd also assume that once it went out of scope there was no memory left allocated. In D am I right to assume I need to manually close the socket but there is no need to worry about the memory? Now the issue is that I now need to call this function more than once every second. I worry that it will create large amounts of uncollected "garbage" which will eventually lead to problems. Am I doing this right? Or is there a better way to do this in D? Thanks. |
June 27, 2017 Re: Advice wanted on garbage collection of sockets for c++ programmer using D | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Burton | On Tuesday, 27 June 2017 at 09:54:19 UTC, John Burton wrote: > I'm coming from a C++ background so I'm not too used to garbage collection and it's implications. I have a function that creates a std.socket.Socket using new and connects to a tcp server, and writes some stuff to it. I then explicitly close the socket, and the socket object goes out of scope. > > I assume that I do need to explicitly call close on the socket as there is no deterministic destructor for class objects. I further assume that the runtime will garbage collect any memory allocated to the socket object at a later time. > > Am I doing this right with GC? In C++ I'd ensure that the Socket class had a destructor that closed the socket and I'd also assume that once it went out of scope there was no memory left allocated. In D am I right to assume I need to manually close the socket but there is no need to worry about the memory? Yes. from the documentation >Immediately drop any connections and release socket resources. Calling shutdown before close is recommended for connection-oriented sockets. The Socket object is no longer usable after close. Calling shutdown() before this is recommended for connection-oriented sockets. The GC (if you use it) will pick up the garbage for you. > Now the issue is that I now need to call this function more than once every second. I worry that it will create large amounts of uncollected "garbage" which will eventually lead to problems. Have a look at automem (https://github.com/atilaneves/automem/) > > Am I doing this right? Or is there a better way to do this in D? > > Thanks. There is also vibe.d if you are looking for more networking stuff. https://github.com/rejectedsoftware/vibe.d Best of luck Nic |
June 27, 2017 Re: Advice wanted on garbage collection of sockets for c++ programmer using D | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Burton | On Tuesday, June 27, 2017 09:54:19 John Burton via Digitalmars-d-learn wrote:
> I'm coming from a C++ background so I'm not too used to garbage collection and it's implications. I have a function that creates a std.socket.Socket using new and connects to a tcp server, and writes some stuff to it. I then explicitly close the socket, and the socket object goes out of scope.
>
> I assume that I do need to explicitly call close on the socket as there is no deterministic destructor for class objects. I further assume that the runtime will garbage collect any memory allocated to the socket object at a later time.
>
> Am I doing this right with GC? In C++ I'd ensure that the Socket class had a destructor that closed the socket and I'd also assume that once it went out of scope there was no memory left allocated. In D am I right to assume I need to manually close the socket but there is no need to worry about the memory?
>
> Now the issue is that I now need to call this function more than once every second. I worry that it will create large amounts of uncollected "garbage" which will eventually lead to problems.
>
> Am I doing this right? Or is there a better way to do this in D?
Arguably, std.socket should have used structs instead of classes for sockets for precisely this reason (though there are some advantages in using inheritance with sockets). But yes, calling close manually is the correct thing to do. Relying on the GC to call a destructor/finalizer is error-prone. There is no guarantee that the memory will ever be freed (e.g. the runtime could choose to not bother doing cleanup on shutdown), and even if the GC does collect it, there are no guarantees about how soon it will do so. However, if you keep allocating memory with the GC, then over time, the GC will collect GC-allocated memory that isn't currently being used so that it can reuse the memory. So, you really don't need to worry about the memory unless it becomes a bottleneck. It will be collected and reused, not leaked.
And if in C++, you would be newing up a socket object each time and then deleting it rather than having the socket on the stack, then that performance could actually be worse than using the GC and having it collect the memory when it determines that it needs more memory.
If you do find that it becomes a bottleneck to be allocating all of these sockets, then you can look into using std.typecons.scoped, which would allocate a class on the stack, but that really only works if you're just dealing with a local variable, and in general, I wouldn't worry about anything like that unless the heap allocations are proving to be a performance problem - particularly because you need to be very careful when using it to avoid screwing up and having memory corruption, because you used an object after it was freed.
- Jonathan M Davis
|
June 27, 2017 Re: Advice wanted on garbage collection of sockets for c++ programmer using D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | On Tuesday, 27 June 2017 at 10:14:16 UTC, Jonathan M Davis wrote:
> On Tuesday, June 27, 2017 09:54:19 John Burton via Digitalmars-d-learn wrote:
>> I'm coming from a C++ background so I'm not too used to garbage collection and it's implications. I have a function that creates a std.socket.Socket using new and connects to a tcp server, and writes some stuff to it. I then explicitly close the socket, and the socket object goes out of scope.
Thank you for the advice everyone.
The hardest part about learning D isn't the language, or how to program, it's unlearning what you know from C++ and learning the proper way to do things in D. I've tried D several times before and eventually stopped when I get to the stage of "how do I do this c++ thing in d" proves to be hard.
Instead this time, I've started writing D programs as "better C" and then slowly started adding in higher level d features. It's going much better as I'm no longer trying so hard to write bad C++ in D :)
|
June 27, 2017 Re: Advice wanted on garbage collection of sockets for c++ programmer using D | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Burton | On Tuesday, 27 June 2017 at 11:43:27 UTC, John Burton wrote:
> On Tuesday, 27 June 2017 at 10:14:16 UTC, Jonathan M Davis wrote:
>> On Tuesday, June 27, 2017 09:54:19 John Burton via Digitalmars-d-learn wrote:
>>> I'm coming from a C++ background so I'm not too used to garbage collection and it's implications. I have a function that creates a std.socket.Socket using new and connects to a tcp server, and writes some stuff to it. I then explicitly close the socket, and the socket object goes out of scope.
>
> Thank you for the advice everyone.
>
> The hardest part about learning D isn't the language, or how to program, it's unlearning what you know from C++ and learning the proper way to do things in D. I've tried D several times before and eventually stopped when I get to the stage of "how do I do this c++ thing in d" proves to be hard.
>
> Instead this time, I've started writing D programs as "better C" and then slowly started adding in higher level d features. It's going much better as I'm no longer trying so hard to write bad C++ in D :)
Heh, there's no reason you can't, you'll just cause a few head scratches when you post code while we figure out what it does. Idiomatic D is rather different to C++ and is centered around ranges + algorithms, but you can write code in pretty much any style. Some of the advanced metaprogramming takes a bit to get your head around.
If you do get stuck do post a question here, we're more than happy to help.
|
June 27, 2017 Re: Advice wanted on garbage collection of sockets for c++ programmer using D | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Burton | On Tuesday, 27 June 2017 at 09:54:19 UTC, John Burton wrote: > Now the issue is that I now need to call this function more than once every second. I worry that it will create large amounts of uncollected "garbage" which will eventually lead to problems. Since nobody has mentioned Allocator, yet: As you seem to know the lifetime of the socket statically, you can just use std.experimental.allocator.{make,dispose} [1]. With regards to reusing the memory: Simply use a freelist allocator [2]. [1] https://dlang.org/phobos/std_experimental_allocator.html#.make [2] https://dlang.org/phobos/std_experimental_allocator_building_blocks_free_list.html |
June 27, 2017 Re: Advice wanted on garbage collection of sockets for c++ programmer using D | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Burton | On Tuesday, 27 June 2017 at 09:54:19 UTC, John Burton wrote: > I assume that I do need to explicitly call close on the socket as there is no deterministic destructor for class objects. Yes. > I further assume that the runtime will garbage collect any memory allocated to the socket object at a later time. Most probably. > > Am I doing this right with GC? In C++ I'd ensure that the Socket class had a destructor that closed the socket and I'd also assume that once it went out of scope there was no memory left allocated. In D am I right to assume I need to manually close the socket but there is no need to worry about the memory? Yes. You can also call a destructor manually with destroy(obj); This avoids having a forest of 'close' methods, who are duplicates of the destructor in spirit, and let's you use destructors like you are accustomed in C++. Generally, it is dangerous to let the GC handle resource release: https://p0nce.github.io/d-idioms/#The-trouble-with-class-destructors > Now the issue is that I now need to call this function more than once every second. I worry that it will create large amounts of uncollected "garbage" which will eventually lead to problems. If this is a problem you can create it on the stack with std.typecons.scoped > Am I doing this right? Or is there a better way to do this in D? > What you are doing it OK. |
June 27, 2017 Re: Advice wanted on garbage collection of sockets for c++ programmer using D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Guillaume Piolat | On Tuesday, 27 June 2017 at 12:29:03 UTC, Guillaume Piolat wrote:
> [...]
Hmm... Isn't it possible to just allocate the object/a pool of objects outside the loop and reuse it? Everybody's proposing other means of allocations which is nice, but I wonder why there is such a need for reallocations in the first place.
Of course the specifics depend on the implementation, maybe it isn't as straightforward. It's just that no allocation is faster than reallocation no matter what reallocation method is used.
|
June 27, 2017 Re: Advice wanted on garbage collection of sockets for c++ programmer using D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Guillaume Piolat | On 6/27/17 8:29 AM, Guillaume Piolat wrote:
> On Tuesday, 27 June 2017 at 09:54:19 UTC, John Burton wrote:
>> Am I doing this right with GC? In C++ I'd ensure that the Socket class had a destructor that closed the socket and I'd also assume that once it went out of scope there was no memory left allocated. In D am I right to assume I need to manually close the socket but there is no need to worry about the memory?
>
> Yes.
> You can also call a destructor manually with destroy(obj);
> This avoids having a forest of 'close' methods, who are duplicates of the destructor in spirit, and let's you use destructors like you are accustomed in C++.
>
> Generally, it is dangerous to let the GC handle resource release:
> https://p0nce.github.io/d-idioms/#The-trouble-with-class-destructors
This is the best to read, it's very tricky for people coming from other languages I think to understand the rules around the GC destructor.
I think you have gotten sound advice from many people, but I wanted to chime in as someone who used the GC to clean up sockets and file handles in a long-running program. Even with all these warnings, it does seem to work. My advice is to close the socket in the destructor if still valid, and then manually close it also. This way you don't leak resources if you miss a close call.
The fundamental problem with closing sockets and other resources with the GC is that the resource management issues and rules for memory are vastly different than those of other resources. The OS can give you vast sums of memory, but will likely limit your ability to keep sockets open. It also keeps the other end potentially locked up. If you try to allocate a new socket and run out of sockets, there is no "socket collection cycle". This is why closing manually is advised.
But I would use a close method, and not destroy(obj). The reason is because often times, you have wrapper types around your socket type, and just one extra level of indirection means the destructor cannot be used to clean up the socket (you are not allowed to access GC-allocated resources in a destructor).
Using std.typecons.RefCounted also can help to ensure destruction of a socket when it's no longer used. But like I said, it's not always possible to use a destructor of a higher level object to clean up a socket.
-Steve
|
June 27, 2017 Re: Advice wanted on garbage collection of sockets for c++ programmer using D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Tuesday, 27 June 2017 at 13:11:10 UTC, Steven Schveighoffer wrote: > But I would use a close method, and not destroy(obj). The reason is because often times, you have wrapper types around your socket type, and just one extra level of indirection means the destructor cannot be used to clean up the socket (you are not allowed to access GC-allocated resources in a destructor). All destructor restrictions do not apply when it's not called by the GC. There really are two categories of destructors: called by the GC and called deterministically. Their usage should not overlap. My reasoning went with the following: 1 - "I should have close() methods so that I don't rely on the GC, and the GC is calling ~this from the wrong thread etc, not everything can be released in this context (eg: OpenGL objects should be released from one thread only). Close methods will call close methods of "owned" objects." 2 - "Uh, oh. Refcounted and Unique and Scoped all use .destroy, so destructors should call close() methods. To avoid double release, close should handle being called several times. The GC will close what I forgot!" 3 - "Actually there is no order of destruction when called by the GC. So I can't release owned objects when called by the GC. Better do nothing when close() is called by the GC, let's detect this. 4 - close() is now identical with ~this (at least for classes). Let's remove the close() method. Crash when a resource is freed by the GC. That's how the GC-proof resource class came to existence, after many destruction bugs, and it let's you use the GC as a detector for non-deterministic destruction. I miss it in @nogc :) https://p0nce.github.io/d-idioms/#GC-proof-resource-class Remember years ago when Alexandrescu suggested the GC shouldn't call heap destructors? That's what we get for having said no at the time. |
Copyright © 1999-2021 by the D Language Foundation