Reputation: 11963
My first impression of readFile
was of a tradeoff between its convenience and the possibility of it leaving file descriptors open longer than needed, with no way to close them. As an experiment I tried the following (highly practical) program, thinking it might choke by trying to maintain a thousand open file descriptors:
main = do
mapM_ (\idx -> readIt) [1..1000]
where readIt = do
contents <- readFile "/etc/passwd"
putChar $ head contents
But it actually does a pretty good job of reclaiming file descriptors; the count never gets above around 70:
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 4
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 5
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 6
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 7
...
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 65
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 66
close(3) = 0
close(4) = 0
close(5) = 0
...
close(54) = 0
close(55) = 0
close(56) = 0
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 3
open("/etc/passwd", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = 4
How is this happening? Is it just that the values of contents
are getting GC'd, and with them the no-longer-referenced file descriptors? Or is there some separate mechanism for managing file descriptor resources? Whatever the mechanism is, it seems to be working pretty well - how can you know when it's best to use hClose
explicitly?
Upvotes: 8
Views: 517
Reputation: 137987
It is better to explicitly close resources yourself, only when you have some low level resource constraint that you can actually enforce manually.
The cases to consider:
finally
or bracket
)Upvotes: 8
Reputation: 5143
The Haddock docs for System.IO
have this to say:
GHC note: a Handle will be automatically closed when the garbage collector detects that it has become unreferenced by the program. However, relying on this behaviour is not generally recommended: the garbage collector is unpredictable. If possible, use an explicit hClose to close Handles when they are no longer required. GHC does not currently attempt to free up file descriptors when they have run out, it is your responsibility to ensure that this doesn't happen.
Upvotes: 6