4

私はいくつかの基本的な haskell ネットワークで遊んでいますが、私を夢中にさせる問題があります。次の非常に単純なサーバー コードでは、メモリ リークが発生しているように見えますが、その理由はわかりません。

まず、accept-method を fork し、すべての受信メッセージをエコーし​​ます。サーバーを Apache Benchmark Tool ab でテストしました。しかし、ab を使用していくつかのテストを行った後、サーバー プロセスでメモリ リークが発生し始めました。10000 リクエストごとに約 1 MB だと思います。

問題は、これはある種の内部ガベージ コレクターの最適化なのか、それとも実際にメモリ リークなのかということです。プログラムを最大 200 MB のメモリ使用量でテストしましたが、まだ増加しています。

この例では、厳密な ByteString を使用しています。私が行った別のテストでは、ハンドルベースの IO を使用していましたが、メモリが合計で 3 MB を超えることはありませんでした。

遅延 IO (ByteString.Lazy) を使用すると、同じ問題が発生しましたが、さらに高速になりました。GHC 7.6 (Windows 8) を使用しています。

echoClient :: Socket -> IO ()
echoClient nextSock = do
    -- Get a stream of bytes
    stream <- NetStrictBS.recv nextSock 120

    -- Echo back
    NetStrictBS.send nextSock stream

    -- Kill the socket
    sClose nextSock


acceptClients :: Socket -> IO ()
acceptClients sock = do

    -- Start with zero index
    loop sock 0
        where

        loop sock sockId = do
            -- Accept socket
            (nextSock, addr) <- accept sock

            -- Disable Nagle
            setSocketOption nextSock NoDelay 1

            -- Process client
            echoClient nextSock

            -- Accept next client
            loop sock (sockId + 1)


main = withSocketsDo $ do

    -- Setup server socket
    sock <- tcpSock
    setSocketOption sock ReuseAddr 1
    bindSocket sock (SockAddrInet 1337 iNADDR_ANY)
    listen sock 128

    -- Fork the acceptor
    forkIO $ acceptClients sock

    print "Server running ... " >> getLine >>= print
4

1 に答える 1

6

同僚と話したところ、問題はこのセクションにあるとのことでした

loop sock (sockId + 1)

評価せずにサンクを構築しているため、ヒープが確実にいっぱいになります。これが、同様の問題に直面している他の人々に役立つことを願っています。

于 2013-06-18T12:06:30.307 に答える