簡體   English   中英

盡管內存已被釋放,Valgrind仍檢測到內存泄漏

[英]Valgrind detects memory leak despite the fact memory has been freed

我有一個文件“ a”,包含2000個字符,僅char“ a”,沒有空格。

然后,我得到了這段代碼,該代碼在循環中運行,將其添加到緩沖區中,如果達到限制,最終將重新分配,並在出現錯誤時釋放strBuffer變量。

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

int main()
{
    int maxS = 200;
    int numericExpression;
    int strLength;


    char *strBuffer;
    strBuffer = malloc(sizeof(char)*maxS+1);
        if(strBuffer == NULL)
        {
            printf("Failed to allocate requested memory!\n");
            free(strBuffer);
            strLength = sizeof(strBuffer);
            printf("Freed %d bytes of memory!\n", strLength);
            exit(99);
        }
        else
        {
            numericExpression = sizeof(char)*maxS+1;
            printf("Alocated: %d Bytes of memory.\n", numericExpression);
        }

    // while simulation

    int fcv = -1;
    int numEx;


    // file opening simulation
    FILE* fd = fopen("a", "r");


    int c;
    while((c=fgetc(fd) != EOF)) // condition to make sure we realloc only once
    {
        fcv++;
        strBuffer[fcv] = c;
        if(fcv == (maxS))   
        {
            printf("Additional memory space required!\n");      
            int strlensize = strlen(strBuffer); 
            numEx = (sizeof(char)*(2*strlensize));


            strBuffer = realloc(strBuffer, numEx);

            if(strBuffer == NULL)
            {
                printf("Failed to allocate requested memory!\n");
                strLength = sizeof(strBuffer);
                free(strBuffer);
                printf("Freed %d bytes of memory!\n", strLength);
                exit(99);
            }
            else
            {
                maxS = numEx;
                printf("Reallocation successful!\n");
                printf("Alocated: %d Bytes of memory.\n", numEx);
            }

        }

    }
    strLength = sizeof(strBuffer);
    free(strBuffer);
    printf("Freed %d bytes of memory!\n", strLength);
}

問題是它最終告訴我,我只釋放了8個字節的內存。 我想這是因為sizeof(strBuffer)沒有響應預期的大小。 當我改用strlen(strBuffer)時,我僅釋放2001個字節。

我想這可能只是打印出釋放的字節數的問題。 我可能做錯了。 因此,也許我只是無法說出我釋放了多少字節。 但是然后我嘗試使用valgrind,它告訴我,我的內存不足,導致內存泄漏。 但是在程序的每個分支中,我都可以釋放strBuffer使用的內存。

當我通過valgrind(“ valgrind ./realloc”)運行它時,它告訴我:

==780== Memcheck, a memory error detector
==780== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==780== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==780== Command: ./realloc
==780== 
Alocated: 201 Bytes of memory.
Additional memory space required!
==780== Invalid read of size 1
==780==    at 0x4C2E0F4: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==780==    by 0x400846: main (in /home/dan/Desktop/test_ifj/realloc)
==780==  Address 0x51fd109 is 0 bytes after a block of size 201 alloc'd
==780==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==780==    by 0x40078C: main (in /home/dan/Desktop/test_ifj/realloc)
==780== 
Reallocation successful!
Alocated: 402 Bytes of memory.
==780== Invalid write of size 1
==780==    at 0x400823: main (in /home/dan/Desktop/test_ifj/realloc)
==780==  Address 0x51fd562 is 0 bytes after a block of size 402 alloc'd
==780==    at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==780==    by 0x400866: main (in /home/dan/Desktop/test_ifj/realloc)
==780== 
Additional memory space required!
Reallocation successful!
Alocated: 806 Bytes of memory.
Additional memory space required!
==780== Conditional jump or move depends on uninitialised value(s)
==780==    at 0x4C2E0F8: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==780==    by 0x400846: main (in /home/dan/Desktop/test_ifj/realloc)
==780== 
Reallocation successful!
Alocated: 804 Bytes of memory.
Freed 8 bytes of memory!
==780== 
==780== HEAP SUMMARY:
==780==     in use at exit: 568 bytes in 1 blocks
==780==   total heap usage: 5 allocs, 4 frees, 2,781 bytes allocated
==780== 
==780== LEAK SUMMARY:
==780==    definitely lost: 0 bytes in 0 blocks
==780==    indirectly lost: 0 bytes in 0 blocks
==780==      possibly lost: 0 bytes in 0 blocks
==780==    still reachable: 568 bytes in 1 blocks
==780==         suppressed: 0 bytes in 0 blocks
==780== Rerun with --leak-check=full to see details of leaked memory
==780== 
==780== For counts of detected and suppressed errors, rerun with: -v
==780== Use --track-origins=yes to see where uninitialised values come from
==780== ERROR SUMMARY: 1200 errors from 3 contexts (suppressed: 0 from 0)

如何正確釋放已分配的內存? 這樣不會引起內存泄漏嗎? 最終-我做錯了嗎,還有更好的方法嗎? 謝謝您的幫助。

問題更新

我遵循了建議,並在1個上下文中將其糾正為3個錯誤。 這是我的代碼現在的樣子:

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

int main()
{
    int maxS = 200;
    int numericExpression;


    char *strBuffer;
    strBuffer = malloc((maxS+1));
        if(strBuffer == NULL)
        {
            printf("Failed to allocate requested memory!\n");
            printf("Freed %d bytes of memory!\n", maxS);
            exit(99);
        }
        else
        {
            numericExpression = sizeof(char)*maxS+1;
            printf("Alocated: %d Bytes of memory.\n", numericExpression);
        }

    // while simulation

    int fcv = -1;
    int numEx;


    // file opening simulation
    FILE* fd = fopen("a", "r");

    if(fd == NULL)
    {
        printf("Error opening a file!\n");

        if(strBuffer != NULL)
        {free(strBuffer);}


        exit(99);
    }


    int c;

    char *tmpBuffer;
    while((c=fgetc(fd)) != EOF) // condition to make sure we realloc only once
    {
        fcv++;
        strBuffer[fcv] = c;

        if(fcv == (maxS))   
        {
            printf("Additional memory space required!\n");      

            numEx = ((2*fcv));


            tmpBuffer = realloc(strBuffer, numEx);
            if(!tmpBuffer)
            {
                free(strBuffer);
                printf("Realloc() failed!\n");
                exit(99);
            }       
            else
            {
                strBuffer = tmpBuffer;
            }   


            if(strBuffer == NULL)
            {
                printf("Failed to allocate requested memory!\n");
                printf("Freed %d bytes of memory!\n", maxS); // well this is questionable, I think
                exit(99);
            }
            else
            {
                maxS = numEx;
                printf("Reallocation successful!\n");
                printf("Alocated: %d Bytes of memory.\n", maxS);
            }

        }

    }

    free(strBuffer);fclose(fd); // ADDED, still errors occur

    printf("Freed %d bytes of memory!\n", maxS);
}

使用相同的valgrind調用(“ valgrind ./realloc”),我得到了:

==1213== Invalid write of size 1
==1213==    at 0x4007FD: main (in /home/dan/Desktop/test_ifj/realloc)
==1213==  Address 0x51fd560 is 0 bytes after a block of size 400 alloc'd
==1213==    at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1213==    by 0x400831: main (in /home/dan/Desktop/test_ifj/realloc)
==1213== 
Additional memory space required!
Reallocation successful!
Alocated: 800 Bytes of memory.
Additional memory space required!
Reallocation successful!
Alocated: 1600 Bytes of memory.
Additional memory space required!
Reallocation successful!
Alocated: 3200 Bytes of memory.
Freed 3200 bytes of memory!
==1213== 
==1213== HEAP SUMMARY:
==1213==     in use at exit: 568 bytes in 1 blocks
==1213==   total heap usage: 6 allocs, 5 frees, 6,769 bytes allocated
==1213== 
==1213== LEAK SUMMARY:
==1213==    definitely lost: 0 bytes in 0 blocks
==1213==    indirectly lost: 0 bytes in 0 blocks
==1213==      possibly lost: 0 bytes in 0 blocks
==1213==    still reachable: 568 bytes in 1 blocks
==1213==         suppressed: 0 bytes in 0 blocks
==1213== Rerun with --leak-check=full to see details of leaked memory
==1213== 
==1213== For counts of detected and suppressed errors, rerun with: -v
==1213== ERROR SUMMARY: 3 errors from 1 contexts (suppressed: 0 from 0)

任何提示可能導致這一問題?

這是你的問題:

strBuffer = realloc(strBuffer, numEx);

如果您對realloc()調用失敗,則它將返回一個空指針,但不會釋放原始的內存分配。

您需要先檢查返回值,如果成功,則將其分配給原始指針:

char *tmpBuffer = realloc(strBuffer, numEx);
if (!tmpBuffer) {
  free(strBuffer);
  puts("realloc() failed");
  exit(1);
}
else {
  strBuffer = tmpBuffer;
}

您的代碼還有其他一些問題,包括:

  • 如果strBuffer為NULL,則沒有意義將其傳遞給free()。

  • sizeof()不是運行時函數,因此它不知道分配了多少內存。

  • strBuffer = malloc(sizeof(char)*maxS+1); 有點草率。 我認為您的意思是strBuffer = malloc(sizeof(char)*(maxS+1)); ,但您只需將strBuffer = malloc(maxS+1); 因為sizeof(char)根據定義為1。

好吧,到目前為止,每個人都為您提供了非常重要的建議,您應該考慮使用它們(主要是tempBuffer )。 但是您的問題是您忘記關閉文件描述符:

fclose(fd);

同樣, sizeof是編譯時間,因此它不能給您動態分配的內存大小,並且strlen需要一個\\n字符才能工作。 計算分配和釋放的內存是一項艱巨的任務,它的解決方案並不是那么簡單。

答案更新

我執行了更新的代碼, 從1個上下文中僅收到1個錯誤 ,可以通過更改以下行來解決: tmpBuffer = realloc(strBuffer, numEx + 1);

除此之外, fclose(fd)之后的所有內存都是可用的。 我在使用gcc 4.8.1的Ubuntu 12.04計算機上。

while((c=fgetc(fd) != EOF))應該是while((c=fgetc(fd)) != EOF) 這樣做的結果是您試圖在字符串中存儲1而不是讀取的字符。

內存問題源於strlen(strBuffer); 您在非空終止的字符串上調用strlen ,這會導致未定義的行為。 (這在valgrind報告中顯示為“ strlen中大小為1的無效讀取)。

要解決此問題,請擺脫strlenSize並執行以下操作:

maxS = 2 * maxS;
strBuffer = realloc(strBuffer, maxS + 1);

請注意,如果要在內存不足的情況下使用“干凈”的valgrind,則需要在將其分配給strBuffer之前檢查realloc的返回值,如提示ossifrage所指出。


注意 您的錯誤處理代碼不正確。 sizeof(strBuffer)查找指針的大小。 您要打印的值為maxS 另外, free(NULL)無效; 在調用exit()塊之后沒有else塊是沒有意義的。

this compiles, and does the job
it includes error handling
it eliminated many meaningless variables
it eliminates the errors in the logic of the OPs code



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

int main()
{
    int maxS = 200; // current allocation size

    char *strBuffer = NULL;
    if( NULL == (strBuffer = malloc(maxS) ) )
    { // then, malloc failed
        perror( "malloc failed" );
        exit(99);
    }

    // implied else, malloc successful

    printf("Alocated: %d Bytes of memory.\n", )maxS+1));

    // file opening simulation
    FILE* fd = fopen("a", "r");
    if(fd == NULL)
    { // then fopen failed
        perror( "fopen failed for file: a" );
        free(strBuffer);
        exit(99);
    }

    // implied else, fopen successful

    int c;       // receives input char from fgetc()
    int fcv = 0; // index into malloc'd memory

    // tmpBuffer used in realloc()
    // so will not lose pointer to already allocated memory
    // in case realloc() fails
    char *tmpBuffer;

    while((c=fgetc(fd)) != EOF)
    {
        strBuffer[fcv] = c;
        fcv++;

        if(fcv >= maxS)
        {
            printf("Additional memory space required!\n");

            if( NULL == ()tmpBuffer = realloc(strBuffer, 2*maxS) )
            {
                perror( "realloc failed" );
                free(strBuffer);
                fclose(fd);
                exit(99);
            }

            // implied else, realloc successful

            maxS *= 2;  // only update after being sure realloc successful
            strBuffer = tmpBuffer;

            printf("Reallocation successful!\n");
            printf("Allocated: %d Bytes of memory.\n", maxS);
        } // end if
    } // end while

    free(strBuffer);
    fclose(fd);

    printf("Freed %d bytes of memory!\n", maxS);
    return( 0 );
} // end function: main

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM