Memory Leak with GHC 9.4.7
Summary
Hello, we have a web service running on a machine and the memory usage increase over multiple days:
(The times were the memory usage goes down is when it is restarted during an update.
However, the live memory and the compact regions are using a fixed amount of memory:
I know that the problem has existed for months but I am don't know when it started.
The server is written using servant and Warp.
Steps to reproduce
I can't share the code but I have tracked the problem quite a bit.
I have tracked down the problem to a endpoint that writes data from the db to disk. It is called every 4 hours.
If I only get the data from the db it desn't leak.
By doing the request in a loop I get an increase in memory use of multiple GB.
The code that leak looks like that:
let f data = do
let bs = getjson data
fp = getFilepath data
liftIO $ BL.writeFile fp bs
return $ partOf data
index <- S.fold_ (\acc (k,v) -> M.insert k v acc) def id $ S.mapM f input
Where the library S is streaming
I tried running it with -M to limit the memory use in case it was just memory that wasn't released to the os but it eventualy crashes because it doesn't have enough memory.
If I remove writeFile
it doesn't leak.
If I then evaluate the bytestring manualy and not write it it leaks
If I run the garbage collector after each call it doesn't leak:
let f data = do
let bs = getjson data
fp = getFilepath data
liftIO $ BL.writeFile fp bs
return $ partOf data
index <- S.fold_ (\acc (k,v) -> M.insert k v acc) def id $ S.mapM S.mapM (f >=> (\x -> Mem.performGC >> pure x)) input
I looked at the fragmentation with ghc-debug and there is barely any pinned data after the request terminate.
Expected behavior
I would expect:
- that the memory use to be the same before running the request and after.
- that evaluating a bytestring and not using it shouldn't make the program leak.
- that adding a call the the gc doesn't remove the leak
Environment
- GHC version used: 9.4.7
Optional:
- Operating System: Debian 11
- System Architecture: x86