Valgrind에 의해 여전히 도달 가능한 누출 감지


154

이 블록에서 언급 된 모든 기능은 라이브러리 기능입니다. 이 메모리 누수를 어떻게 해결할 수 있습니까?

" 여전히 접근 가능 "범주 아래에 나열됩니다 . (매우 유사하지만 크기가 다른 4 개가 더 있습니다)

 630 bytes in 1 blocks are still reachable in loss record 5 of 5
    at 0x4004F1B: calloc (vg_replace_malloc.c:418)
    by 0x931CD2: _dl_new_object (dl-object.c:52)
    by 0x92DD36: _dl_map_object_from_fd (dl-load.c:972)
    by 0x92EFB6: _dl_map_object (dl-load.c:2251)
    by 0x939F1B: dl_open_worker (dl-open.c:255)
    by 0x935965: _dl_catch_error (dl-error.c:178)
    by 0x9399C5: _dl_open (dl-open.c:584)
    by 0xA64E31: do_dlopen (dl-libc.c:86)
    by 0x935965: _dl_catch_error (dl-error.c:178)
    by 0xA64FF4: __libc_dlopen_mode (dl-libc.c:47)
    by 0xAE6086: pthread_cancel_init (unwind-forcedunwind.c:53)
    by 0xAE61FC: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126)

캐치 : 프로그램을 실행 한 후에는 메모리 누수가 발생하지 않았지만 Valgrind 출력에 한 줄이 추가되었는데 이전에는 없었습니다.

munmap ()으로 인해 /lib/libgcc_s-4.4.4-20100630.so.1의 0x5296fa0-0x52af438에서 심볼 무시

누출을 해결할 수없는 경우 누군가 munmap () 라인으로 인해 Valgrind가 "아직 도달 할 수있는"누출을보고하는 이유를 적어도 설명 할 수 있습니까?

편집하다:

최소 테스트 샘플은 다음과 같습니다.

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *runner(void *param) {
    /* some operations ... */
    pthread_exit(NULL);
}

int n;

int main(void) {

    int i;
    pthread_t *threadIdArray;

    n=10; /* for example */

    threadIdArray = malloc((n+n-1)*sizeof(pthread_t));  

    for(i=0;i<(n+n-1);i++) {
        if( pthread_create(&threadIdArray[i],NULL,runner,NULL) != 0 ) {
            printf("Couldn't create thread %d\n",i);
            exit(1);
        }
    }


    for(i=0;i<(n+n-1);i++) {
        pthread_join(threadIdArray[i],NULL);
    }

    free(threadIdArray);

    return(0);
}

로 실행 :

valgrind -v --leak-check=full --show-reachable=yes ./a.out

답변:


378

"메모리 누수"를 정의하는 방법은 여러 가지가 있습니다. 특히, 프로그래머들 사이에서 일반적으로 사용되는 "메모리 누수"에 대한 두 가지 주요 정의가 있습니다.

"메모리 누수"에 대해 가장 일반적으로 사용되는 정의는 "메모리가 할당되었고 프로그램이 종료되기 전에 메모리가 해제되지 않았습니다."입니다. 그러나 많은 프로그래머들은이 정의에 맞는 특정 유형의 메모리 누수가 실제로 어떤 종류의 문제도 일으키지 않으므로 진정한 "메모리 누수" 로 간주되어서는 안된다고 주장합니다 .

"메모리 누수"에 대한 더 엄격하고 (더 유용한) 정의는 " 프로그램이 더 이상 할당 된 메모리 블록에 대한 포인터를 갖지 않기 때문에 메모리가 할당되었고 이후에 해제 될 수 없음 "입니다. 즉, 더 이상 포인터가없는 메모리를 비울 수 없습니다. 따라서 이러한 메모리는 "메모리 누수"입니다. Valgrind는 "메모리 누수"라는 용어를보다 엄격하게 정의합니다. 이는 특히 오래 지속되는 프로세스에서 상당한 힙 고갈을 유발할 수있는 누출 유형입니다.

Valgrind의 누수 보고서에서 "여전히 도달 할 수있는"범주는 "메모리 누수"의 첫 번째 정의에만 맞는 할당을 나타냅니다. 이 블록은 해제되지 않았지만 프로그램이 여전히 해당 메모리 블록에 대한 포인터를 추적하고 있었기 때문에 해제 될 수있었습니다 (프로그래머가 원한다면).

일반적으로 "여전히 도달 할 수있는"블록에 대해 걱정할 필요가 없습니다. 실제 메모리 누수가 발생할 수 있는 일종의 문제는 아닙니다 . 예를 들어, 일반적으로 "여전히 도달 할 수있는"블록에서 힙이 소진 될 가능성은 없습니다. 이러한 블록은 일반적으로 일회성 할당이기 때문에 참조는 프로세스 수명 기간 동안 유지됩니다. 프로그램을 통해 할당 된 모든 메모리를 해제 할 수는 있지만 프로세스가 종료 된 후 운영 체제가 프로세스의 모든 메모리를 회수하므로 일반적으로 그렇게하면 실질적인 이점이 없습니다. 이것을 과 대조 메모리 누수 (고정되지 않은 상태로 남겨두면 프로세스가 오래 실행되는 경우 메모리가 부족해 지거나 프로세스가 필요한 것보다 훨씬 많은 메모리를 소비하게 함)

아마도 모든 할당에 일치하는 "frees"가 있는지 확인하는 것이 유용한 유일한 시점은 누출 감지 도구가 어느 블록에 "여전히 도달 할 수 있는지"(Valgrind가이를 수행 할 수 있는지) 알 수 없거나 운영 체제가 모든 것을 회수하지 못하는 경우입니다. 종료 프로세스의 메모리 (Valgrind가 포팅 한 모든 플랫폼)


munmap ()이 무엇을하고 있는지 아직도 "아직 도달 할 수있는"블록을 사라지게 할 수 있습니까?

3
@crypto : munmap공유 객체를 언로드 한 결과 호출 될 수 있습니다 . 그리고 공유 객체가 사용하는 모든 리소스는 언로드되기 전에 해제 될 수 있습니다. 이 경우 '여전히 도달 할 수있는 도구'가 해제되는 이유를 설명 할 수 munmap있습니다. 그래도 여기서 추측하고 있습니다. 여기에 말할 정보가 충분하지 않습니다.
Dan Molding

3
"여전히 도달 할 수있는"메모리가 메모리 누수로 간주 될 수있는 경우 : 힙 할당 메모리에 대한 포인터를 값으로 추가하는 해시 테이블이 있다고 가정하십시오. 테이블에 새 항목을 계속 삽입하지만 더 이상 필요하지 않은 항목을 제거하고 해제하지 않으면 해당 메모리가 일반적으로 "여전히 도달 할 수있는"경우 힙 메모리 이벤트가 유출되어 무기한 증가 할 수 있습니다. Java 또는 기타 가비지 수집 언어에서 발생할 수있는 메모리 누수의 경우입니다.
lvella

STL이 생성 한 "여전히 도달 할 수있는"블록에 대해서는 valgrind FAQ에서이 답변을 참조하십시오. valgrind.org/docs/manual/faq.html#faq.reports
John Perry

5
"많은 프로그래머들은 (리치 한 메모리가) 실제로 [a] 문제를 일으키지 않으므로 진정한 메모리 누수로 간주되어서는 안된다고 주장한다" -Lol ... 그런 종류의 메모리 누수로 네이티브 DLL을 빌드 한 다음 Java 또는 .Net에서 사용하십시오. Java 및 .Net은 프로그램 수명 동안 DLL을 수천 번로드 및 언로드합니다. DLL이 다시로드 될 때마다 조금 더 많은 메모리가 누출됩니다. 장기 실행 프로그램은 결국 메모리가 부족합니다. 데비안의 OpenJDK 관리자를 화나게합니다. 그는 OpenSSL의 "양성"메모리 누수에 대해 논의하는 동안 OpenSSL 메일 링리스트에서도 동일하게 말했습니다.
jww

10

하단에 pthread 제품군의 일부 루틴이 있지만 (그 특정 것을 모르는 경우) 실행이 종료되는 결합 가능한 스레드를 시작한 것으로 추측됩니다.

호출 할 때까지 해당 스레드의 종료 상태 정보를 계속 사용할 수 있습니다 pthread_join. 따라서 메모리는 프로그램 종료시 손실 레코드로 유지되지만 pthread_join액세스하는 데 사용할 수 있기 때문에 여전히 도달 할 수 있습니다 .

이 분석이 올 바르면 스레드를 분리하거나 프로그램을 종료하기 전에 결합하십시오.

편집 : 샘플 프로그램을 실행하고 (몇 가지 명백한 수정 후) 오류는 없지만 다음과 같습니다.

==18933== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
--18933-- 
--18933-- used_suppression:      2 dl-hack3-cond-1
--18933-- used_suppression:      2 glibc-2.5.x-on-SUSE-10.2-(PPC)-2a

dl-일이 당신이 보는 것과 많이 닮았 기 때문에 에 대한 억제 파일과 관련하여 해결책이있는 알려진 문제가 있다고 생각합니다 valgrind. 시스템이 최신 상태가 아니거나 배포판에서 이러한 정보를 유지하지 못할 수 있습니다. (내는 우분투 10.4, 64 비트입니다)


당신처럼 0 오류가 발생합니다. "누설"에 대한 정보는 누출 요약을 확인하십시오.

@ 암호 : 이해가 안됩니다. 내가 가진 것과 같은 억압이 있다는 뜻입니까?
Jens Gustedt

used_suppression : 14 dl-hack3-cond-1 <-그것이 내가 얻는 것

6

무슨 still reachable뜻 인지 이해하지 못하는 것 같습니다 .

뭐든지 still reachable입니다 하지 누출. 당신은 그것에 대해 아무것도 할 필요가 없습니다.


24
이것은 Valgrind가 제공 한 다른 동사와 상충되며 기술적으로 부정확합니다. 프로그램 종료시 메모리가 "여전히 도달 가능"하여 누출이 발생할 수 있습니다. 프로그램 종료 후 메모리를 제대로 정리하지 못하는 RTOS에서 실행되도록 코드를 디버깅하는 경우 어떻게됩니까?
Toymakerii

4
불행히도, 항상 그런 것은 아닙니다. 예를 들어 손실 된 파일 설명자는 메모리 누수로 계산할 수 있지만 valgrind는이를 설명하는 포인터가 여전히 시스템 테이블 내에서 액세스 할 수 있기 때문에 "계속 도달 할 수있는"것으로 분류합니다. 그러나 디버깅을 위해 실제 진단은 "메모리 누수"입니다.
Cyan

손실 된 파일 디스크립터는 정의에 의한 메모리 누수 가 아닙니다 . 어쩌면 잃어버린 FILE포인터 에 대해 이야기하고 있습니까?
러시아어

6

"여전히 도달 가능"에 대한 적절한 설명은 다음과 같습니다.

"여전히 도달 가능"은 전역 및 정적 지역 변수에 할당 된 누출입니다. valgrind는 전역 변수와 정적 변수를 추적하기 때문에 "한 번만 잊어 버린"할당 된 메모리 할당을 제외 할 수 있습니다. 전역 변수는 할당을 한 번 할당했지만 할당이 무기한으로 증가하지 않는다는 의미에서 할당이 "누설"이 아니라는 것을 다시 할당하지 않았습니다. 그것은 엄격한 의미에서 여전히 누출이지만, pedantic하지 않으면 일반적으로 무시할 수 있습니다.

할당이 할당되고 해제되지 않은 지역 변수는 거의 항상 누출입니다.

여기에 예가 있습니다

int foo(void)
{
    static char *working_buf = NULL;
    char *temp_buf;
    if (!working_buf) {
         working_buf = (char *) malloc(16 * 1024);
    }
    temp_buf = (char *) malloc(5 * 1024);

    ....
    ....
    ....

}

Valgrind는 working_buf를 "여전히 도달 할 수있는-16k"로, temp_buf를 "definitely lost-5k"로보고합니다.


-1

미래의 독자들에게 "여전히 접근 가능"은 파일과 같은 것을 닫는 것을 잊었을 수 있습니다. 원래 질문에서는 그렇게 보이지는 않지만 항상 그렇게했는지 확인해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.