2014-07-24 3 views
37

JSON 요청을 수신하여 처리하는 하스켈 데몬에서 작업 중입니다. 데몬의 작업이 복잡하기는하지만 주요 구조는 의도적으로 단순하게 유지됩니다. 내부 상태는 데이터 구조가있는 IORef이고 모든 스레드는이 IORef에 대한 원자 적 작업을 수행합니다. 그런 다음 방아쇠를 당길 때 가치가있는 스레드가 있습니다.힙 프로파일 링에 표시되지 않는 메모리 누수 디버깅

문제는 데몬이 메모리를 유출하고 있는데 그 이유를 찾을 수 없다는 것입니다. 이것은 확실히 요청과 관련이 있습니다. 데몬이 초당 요청을 여러 번 받으면 1MB/s와 같은 것이 유출됩니다 (Linux 도구에서보고 한 것). 메모리 소비는 꾸준히 증가합니다. 요청이 없으면 메모리 소비는 일정하게 유지됩니다.

내가 GHC 프로파일 링에서 보여주지 않은 것은 무엇인가. 어느 나는 프로파일 매개 변수에 뭔가를 누락하거나, 메모리는 다른 무언가에 의해 소비된다

실행 +RTS -hc -xt -p과 :

screenshot of profiler output

실행 +RTS -hr -xt -p과 :

screenshot of profiler output

이 테스트를 실행하는 동안 데몬은 이후 1GB 이상을 소비합니다. 따라서 프로파일 링 데이터는 실제로 소비 된 메모리와 순서대로 일치하지 않습니다. (RTS, GC 및 프로파일 링 자체가 실제 메모리 사용량에 추가되지만이 차이는 너무 커서 증가하는 소비에 해당하지 않음을 이해합니다.) rnf 이미 시도했습니다. IORef 안에있는 데몬의 상태 데이터와 구문 분석 된 JSON 요청 (JSON 문자열의 일부가 어딘가에 보관되는 것을 방지하기 위해)은 많이 성공하지 못했습니다.

모든 아이디어 나 제안을 환영합니다.

업데이트 : 데몬이 -threaded없이 실행 중이므로 OS 레벨 스레드가 없습니다.

GC의 통계는 리눅스에 의해보고 된 숫자보다 힙 프로파일에 훨씬 더 가까이 있습니다

Alloc Copied  Live GC GC  TOT  TOT Page Flts 
    bytes  bytes  bytes user elap user elap 
[...] 
    5476616  44504 2505736 0.00 0.00 23.21 410.03 0 0 (Gen: 0) 
35499296  41624 2603032 0.00 0.00 23.26 410.25 0 0 (Gen: 0) 
51841800  46848 2701592 0.00 0.00 23.32 410.49 0 0 (Gen: 0) 
31259144  36416 2612088 0.00 0.00 23.40 410.61 0 0 (Gen: 0) 
53433632  51976 2742664 0.00 0.00 23.49 412.05 0 0 (Gen: 0) 
48142768  50928 2784744 0.00 0.00 23.54 412.49 0 0 (Gen: 0) 
[...] 

업데이트 2 : 나는 문제의 근원을 발견, 메모리 누수가 발생합니다 handleToFd (유닉스 라이브러리의 경우 this issue 참조). 난 그냥 어떻게 더 효과적으로 누수 (외국 코드에서 발생)를 정확하게 지적하는 것이 가능할 지 궁금해. 당신이 그것을 컴파일하는 경우

+6

누출 메모리가 GHC 힙 외부에 할당 된 바이트 체크에있는 것으로 추측합니다. 힙 프로파일은 결국 GHC가 알고있는 것을 보여줍니다. – Carl

+0

@Carl 그리고 ByteString 할당에 대해 어떻게 든 이해할 수있는 방법이 있습니까? –

+0

FFI 인터페이스에서 어떤 일이 벌어지고 있는지 이해하는 것 외에는 알지 못합니다. 네트워킹을 위해 사용하는 라이브러리가 무엇이든 의심하십시오. – Carl

답변

1

나는 하스켈 데몬 자체에 익숙하지 오전하지만, 귀하의 질문에 대답 "더 효과적으로 누수를 정확하게 할 수있을 것입니다 방법",

valgrind --leak-check=yes haskelldaemon (더 사용할 수있을 누출이 공유 라이브러리에 발생하는 경우 디버그 정보),

OR로,

LD_PRELOAD="yourlibrary.so" valgrind your-executable을 시도합니다.