Valgrind tarafından hala ulaşılabilir sızıntı tespit edildi


155

Bu blokta belirtilen tüm fonksiyonlar kütüphane fonksiyonudur. Bu bellek sızıntısını nasıl düzeltebilirim?

" Hala erişilebilir " kategorisi altında listelenir . (Çok benzer, ancak değişen boyutlarda 4 tane daha var)

 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)

Catch: Programımı çalıştırdıktan sonra bellek sızıntısı vermedi, ancak daha önce mevcut olmayan Valgrind çıktısında bir satır daha vardı:

Munmap () nedeniyle /lib/libgcc_s-4.4.4-20100630.so.1 dosyasındaki 0x5296fa0-0x52af438 adresindeki syms atma

Sızıntı giderilemezse, en azından birisi munmap () hattının neden Valgrind'in 0 "hala ulaşılabilir" sızıntı rapor etmesine neden olduğunu açıklayabilir mi?

Düzenle:

İşte minimal bir test örneği:

#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);
}

Şununla çalıştır:

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

Yanıtlar:


379

"Bellek sızıntısı" tanımlamanın birden fazla yolu vardır. Özellikle, programcılar arasında yaygın olarak kullanılan iki "bellek sızıntısı" tanımı vardır.

Yaygın olarak kullanılan ilk "bellek sızıntısı" tanımı, "Bellek ayrılmış ve daha sonra program sonlandırılmadan serbest bırakılmamıştır." Bununla birlikte, birçok programcı (haklı olarak) bu tanıma uyan belirli bellek sızıntısı türlerinin aslında herhangi bir sorun yaratmadığını ve bu nedenle gerçek "bellek sızıntısı" olarak görülmemeleri gerektiğini savunmaktadır .

"Bellek sızıntısı" bir tartışmalı katı (ve daha faydalı) tanımı "bellek tahsis edilmiş ve bir olamaz program artık ayrılan bellek bloğu için herhangi bir işaretçiler, çünkü daha sonra serbest". Başka bir deyişle, artık hiçbir işaretçiye sahip olmadığınız belleği boşaltamazsınız. Dolayısıyla bu tür bir bellek bir "bellek sızıntısı" dır. Valgrind "bellek sızıntısı" teriminin bu daha katı tanımını kullanmaktadır. Bu, özellikle uzun ömürlü işlemler için önemli ölçüde yığın tükenmesine neden olabilecek sızıntı türüdür.

Valgrind'in sızıntı raporundaki "hala erişilebilir" kategorisi, yalnızca "bellek sızıntısı" nın ilk tanımına uyan ayırmaları ifade eder. Bu bloklar serbest bırakılmadı, ancak program hala bu bellek bloklarına işaretçileri takip ettiği için serbest bırakılmış olabilirler (programcı isteseydi).

Genel olarak, "hala ulaşılabilir" bloklar hakkında endişelenmenize gerek yoktur. Gerçek bellek sızıntılarının neden olabileceği bir sorun teşkil etmiyorlar . Örneğin, normal olarak "hala ulaşılabilir" bloklardan öbek tükenmesi potansiyeli yoktur. Bunun nedeni, bu blokların genellikle tek seferlik tahsisler olması ve referansların sürecin ömrü boyunca tutulmasıdır. Geçip programınızın ayrılan tüm belleği serbest bıraktığından emin olsanız da , genellikle işlem sona erdikten sonra işletim sistemi sürecin tüm belleğini geri kazanacağından pratik bir yarar yoktur. Bunu doğru ile karşılaştır sabitlenmezse, yeterince uzun süre çalışırsa bir işlemin belleğinin tükenmesine neden olabilecek veya bir işlemin gereğinden fazla bellek tüketmesine neden olacak bellek sızıntıları.

Muhtemelen, tüm ayırmaların eşleşen "serbest bırakmalar" olmasını sağlamak için yararlı olan tek zaman, kaçak tespit araçlarınız hangi blokların "hala erişilebilir" olduğunu söyleyemiyorsa (ancak Valgrind bunu yapabilir) veya işletim sisteminizin tümünü geri almıyorsa bir sonlandırma işleminin belleği (Valgrind'in bunu yapmak için taşındığı tüm platformlar).


"hala ulaşılabilir" blokların kaybolmasını sağlayan munmap () 'nin ne yaptığını tahmin edebilir misiniz?

3
@crypto: munmapPaylaşılan bir nesnenin kaldırılması sonucu çağrılabilir. Paylaşılan nesne tarafından kullanılan tüm kaynaklar, kaldırılmadan önce serbest bırakılıyor olabilir. Bu "hala reachables" neden içinde serbest alıyorsanız açıklayabilir munmapdurumda. Ben sadece burada spekülasyon yapıyorum. Burada kesin olarak söyleyecek yeterli bilgi yok.
Dan Moulding

3
"Yine de erişilebilir" belleğin bellek sızıntısı olarak değerlendirilebileceği bir durum: ayrılan belleği yığın olarak değer olarak işaretlediğiniz bir karma tablonuz olduğunu varsayalım. Tabloya yeni girişler eklemeye devam ederseniz, ancak artık ihtiyacınız olmayanları kaldırmayacak ve serbest bırakmayacaksanız, bellek sürekli olarak "ulaşılabilir" ise yığın bellek olayına sızarak süresiz olarak büyüyebilir. Bu, Java veya diğer çöp toplanmış dillerde sahip olabileceğiniz bellek sızıntısı durumudur.
lvella

STL tarafından oluşturulan "hala erişilebilir" bloklarla ilgili valgrind SSS bölümündeki bu cevaba da bakınız. valgrind.org/docs/manual/faq.html#faq.reports
John Perry

5
"Birçok programcı (haklı olarak) [sızdırılmış bellek] aslında [a] sorun teşkil etmiyor ve bu nedenle gerçek bellek sızıntıları olarak kabul edilmemelidir" - Lol ... Bu tür bir bellek sızıntısı ile yerel bir DLL oluşturun ve sonra Java veya .Net kullanmasını sağlayın. Java ve .Net bir programın ömrü boyunca binlerce kez DLL yükleyip kaldırır. DLL her yüklendiğinde biraz daha fazla bellek sızıntısı olacak. Uzun süren programlar sonunda belleğin bitmesine neden olur. Debian'ın OpenJDK sürdürücüsünü çıldırtıyor. Aynı şeyi OpenSSL'nin "iyi huylu" bellek sızıntılarını tartışırken de OpenSSL posta listesinde söyledi.
jww

10

Altta pthread ailesinden bazı rutin olduğu için (ama o özel olanı bilmiyorum), tahminim yürütmeyi sonlandıran birleştirilebilir olarak bazı iş parçacığı başlatmış olacaksınız.

Bu iş parçacığının çıkış durumu bilgileri, siz arama yapana kadar saklanır pthread_join. Bu nedenle, program sonlandırıldığında bellek bir kayıp kaydında tutulur, ancak pthread_joinerişmek için kullanabileceğiniz için hala erişilebilir .

Bu analiz doğruysa, bu iş parçacıklarını ayrılmış olarak başlatın veya programınızı sonlandırmadan önce bunlara katılın.

Düzenleme : Örnek programınızı çalıştırdım (bazı açık düzeltmelerden sonra) ve hatalarım yok ama aşağıdakiler

==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

Yana dl-şey benzer, çok gördüklerinizin görüyorum ki sen bastırma dosyasının açısından bir çözümü vardır bilinen bir sorun olduğunu fark olduğunu tahmin valgrind. Belki sisteminiz güncel değil veya dağıtımınız bu şeyleri sürdürmüyor. (Benimki ubuntu 10.4, 64bit)


Tıpkı senin gibi 0 hata alıyorum. Lütfen "kaçaklar" hakkında bilgi için kaçak özetini kontrol edin.

@crypto: Anlamıyorum. Yani benimle aynı baskılara mı sahipsin?
Jens Gustedt

used_suppression: 14 dl-hack3-cond-1 <- İşte bunu elde ediyorum

6

Ne anlama still reachablegeldiğini anlamıyorsunuz .

Her şey still reachableolduğu değil bir sızıntı. Bu konuda bir şey yapmanıza gerek yok.


24
Bu teknik olarak yanlış olduğu kadar Valgrind tarafından sağlanan diğer döküntülerle de çelişmektedir. Bellek, program çıkışında "hala erişilebilir" ve bu nedenle potansiyel olarak bir sızıntıdır. Program çıkışından sonra belleği iyi temizlemeyen bir RTOS üzerinde çalıştırmak için kodda hata ayıklasaydınız ne olurdu?
Mart'ta Toymakerii

4
Ne yazık ki, bu her zaman doğru değildir. Örneğin Kayıp Dosya tanımlayıcıları bellek sızıntısı olarak sayılabilir, ancak valgrind bunları "hala erişilebilir" olarak sınıflandırır; Ancak hata ayıklama amacıyla, gerçek tanı bir "bellek sızıntısı" dır.
Camgöbeği

Kayıp dosya tanımlayıcıları tanım gereği bellek sızıntısı değildir . Belki kayıp FILEişaretçilerden bahsediyorsunuz ?
Çalışan Rus

6

İşte "hala ulaşılabilir" ifadesinin doğru açıklaması:

"Hala erişilebilir" genel ve statik-yerel değişkenlere atanan sızıntılardır. Valgrind global ve statik değişkenleri izlediğinden, "bir kez ve unut" olarak atanan bellek ayırmalarını hariç tutabilir. Global bir değişken bir kez tahsis tahsis etti ve tahsisin süresiz olarak büyümemesi anlamında tipik olarak bir "sızıntı" olmadığını asla yeniden atamadı. Hala katı anlamda bir sızıntıdır, ancak bilgiçlik yapmazsanız genellikle göz ardı edilebilir.

Tahsis edilen ve serbest olmayan yerel değişkenler neredeyse her zaman sızıntıdır.

İşte bir örnek

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 dosyasını "hala ulaşılabilir - 16k" ve temp_buf'u "kesinlikle kaybetti - 5k" olarak rapor edecektir.


-1

Gelecekteki okuyucular için "Hala Ulaşılabilir", dosya gibi bir şeyi kapatmayı unuttuğunuz anlamına gelebilir. Orijinal soruda öyle görünmese de, her zaman bunu yaptığınızdan emin olmalısınız.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.