Bellek Ayırmada Hata Ayıklama
Önceki Yazılım Verisine Saklama Alanı Ayrılması Sonraki
Bellek Ayırmada Hata Ayıklama
Özdevimli bellek ayırmasında bellek artıklarının bulunması çöp toplayıcı kullanılmayan dillerle yazılım geliştirilirken oldukça karmaşık bir iştir. Uzun süre çalışan yazılımlar özdevimli olarak ayırdıkları nesnelerin işleri bittiğinde serbest bırakılmalarını sağlamalıdır. Aksi takdirde sistem belleğinin tükenmesi sözkonusu olabilir.
GNU C kütüphanesindeki malloc gerçeklemesi bu tür artıkların saptanması ve konumlarının bulunmasıyla ilgili bazı bilgiler sağlar. Bunu yapacak uygulama bir ortam değişkeni ile etkinleştirilen bir özel kipte başlatılmalıdır. Hata ayıklama kipi etkinleştirilirse yazılım için hiçbir hız cezası kesilmez.
İzleme işlevselliğinin kurulması
void mtrace
(void)
işlev
mtrace işlevi çağrıldığında MALLOC_TRACE isimli ortam değişkenine bakar. Bu değişkenin bir dosya ismi içereceği kabul edilir. Kullanıcının yazma izni olmalıdır. Dosya zaten mevcutsa içeriği silinir. Ortam değişkeni yoksa ya da değeri yazmak için açılabilir bir geçerli dosya ismi değilse hiçbir şey yapılmaz. malloc ve benzerlerinin davranışı değiştirilmez. Belli sebeplerle SUID veya SGID'li uygulamalar için de bu durum geçerlidir.
İsimli dosya başarıyla açılırsa, mtrace işlevi malloc, realloc ve free işlevleri için kancalar oluşturur. Bundan sonra bu işlevlerin tüm kullanımları izlenir ve dosyaya listelenir. İzlenen işlevlere yapılan tüm çağrılar için artık bir hız cezası vardır. Yani normal kullanım için izleme etkinleştirilmemelidir.
Bu işlev bir GNU oluşumudur ve genelde diğer sistemler için kullanılabilir değildir. İşlev mcheck.h başlık dosyasında bildirilmiştir.
void muntrace
(void)
işlev
muntrace işlevi malloc çağrılarının izlenmesini etkinleştiren mtrace çağrısından sonra çağrılabilir. Başarılı bir mtrace çağrısı yoksa muntrace hiçbir şey yapmaz.
Aksi takdirde malloc, realloc ve free işlevleri için oluşturulan kancaları iptal eder ve izleme dosyasını kapatır. İzlenen bir çağrı kalmadığından yazılım tam gaz çalışır.
Bu işlev bir GNU oluşumudur ve genelde diğer sistemler için kullanılabilir değildir. İşlev mcheck.h başlık dosyasında bildirilmiştir.
Örnek Yazılım Parçaları
İzleme işlevselliği yazılımın çalışma anı davranışını açıklamasa bile tüm yazılımlarda mtrace çağrısı yapmak iyi fikir değildir. Olaya bir bütün olarak bakarsak, siz yazılımınızda mtrace kullanarak hata ayıklamak istediğinizde, sistemde çalışan tüm diğer yazılımların da malloc çağrıları izleniyorsa, çıktı dosyası tüm yazılımlar için tek olacağından hata ayıklaması kullanışsız olacaktır. Bu nedenle, sadece hata ayıklama için derlenmişse tek mtrace çağrısı olmalı ve bir yazılım şöyle başlamalıdır:
#include <mcheck.h>

int main (int argc, char *argv[])
{
#ifdef DEBUGGING
  mtrace ();
#endif
  …
}
Yazılımın çalışması sırasında çağrıları izlemek isterseniz gereken tek şey budur. Ayrıca, izlemeyi istediğiniz bir anda muntrace ile durdurabilir ve yeni bir mtrace çağrısı ile izlemeyi yeniden başlatabilirsiniz. Ancak, çağrılmamış işlev çağrıları olabileceğinden bu istenmeyen sonuçlara yol açabilir.
Not
İzleme işlevselliği sadece uygulama yazılımları için değildir, kütüphaneler de (hatta C kütüphanesinin kendisi de) bu işlevleri kullanabilir.
Bu durum, yazılım sonlanmadan önce muntrace çağrısı yapmanın neden iyi bir fikir olmadığı hakkında da bir fikir verir. Kütüphaneler sadece yazılımın main işlevinin dönüşü veya bir exit çağrısından sonra yazılımın sonlandırıldığı hakkında bilgilendirilir. Dolayısıyla bu olmadan kütüphaneler kullandıkları belleği serbest bırakamazlar.
En iyisi, yazılımın hemen başlarında bir kere mtrace çağrısı yapmak ve hiç muntrace çağrısı yapmamaktır. Bu durumda yazılımın hemen hemen tüm malloc işlevlerinin (yazılımın yapılandırıcıları tarafından çalıştırılanlar ile kütüphanelerin kullandıkları hariç) kullanımları izlenir.
Bellek Hata Ayıklaması için İpuçları
Durumu biliyorsunuz. Yazılım hata ayıklama için hazırlandı ve tüm hata ayıklama oturumları iyi çalışmakta. Ancak hata ayıklaması olmaksızın başlattığınızda hata gördünüz. Bir örnek olarak, hata ayıklamayı kapattığınızda bir bellek artığı görmüş olun. Böyle durumları sezebilirseniz kazanma şansınız olabilir. Aşağıdaki küçük yazılımda bazı şeylerin eşdeğerlerini basitçe kullanalım:
#include <mcheck.h>
#include <signal.h>

static void
enable (int sig)
{
  mtrace ();
  signal (SIGUSR1, enable);
}

static void
disable (int sig)
{
  muntrace ();
  signal (SIGUSR2, disable);
}

int
main (int argc, char *argv[])
{
  …

  signal (SIGUSR1, enable);
  signal (SIGUSR2, disable);

  …
}
Vs., yazılımcı ortamda MALLOC_TRACE'i ayarlayarak yazılımda bellek hata ayıklamasını başlatabilir. Çıktı şüphesiz ilk sinyalden önce oluşan ayırmaları göstermez ama bir bellek artığı varsa yine de gösterilecektir.
İzlerin Yorumlanması
Çıktıya bakarsanız buna benzeyecektir:
= Start
 [0x8048209] - 0x8064cc8
 [0x8048209] - 0x8064ce0
 [0x8048209] - 0x8064cf8
 [0x80481eb] + 0x8064c48 0x14
 [0x80481eb] + 0x8064c60 0x14
 [0x80481eb] + 0x8064c78 0x14
 [0x80481eb] + 0x8064c90 0x14
= End
İzleme dosyası bir insan tarafından okunup anlamlandırılmayacağı için bu satırların ne anlama geldiğinin bir önemi yoktur. Bu nedenle, okunabilirliğe dikkat edilmemiştir. Bu iş için GNU C kütüphanesi ile birlikte bu izleri yorumlayan ve kullanıcı dostu bir yolla özetleyen bir uygulama gelir. Bu uygulamanın ismi mtrace'dir (aslında bir Perl betiğidir) ve bir ya da iki argüman alır. İzleme çıktısının dosya ismi mutlaka belirtilmelidir. İsteğe bağlı olarak verilebilecek ikinci argüman izleme dosyasının isminden önce verilmesi gereken ve bu izi üreten yazılımın ismidir.
drepper$ mtrace tst-mtrace log
No memory leaks.
Burada tst-mtrace isimli yazılım çalıştırılmış ve log isimli bir izleme dosyası üretilmiştir. mtrace uygulaması tarafından basılan ileti kodla ilgili bir sorun olmadığını göstermiş ve ardından ayrılan tüm bellek serbest bırakılmıştır.
Biz mtrace uygulamasını yukardaki örnek izleme dosyası için çalıştırırsak farklı bir çıktı alırız:
drepper$ mtrace errlog
- 0x08064cc8 Free 2 was never alloc'd 0x8048209
- 0x08064ce0 Free 3 was never alloc'd 0x8048209
- 0x08064cf8 Free 4 was never alloc'd 0x8048209

Memory not freed:
-----------------
   Address     Size     Caller
0x08064c48     0x14  at 0x80481eb
0x08064c60     0x14  at 0x80481eb
0x08064c78     0x14  at 0x80481eb
0x08064c90     0x14  at 0x80481eb
mtrace uygulamasını tek argümanla çağırdık ve bu durumda betik izlerde verilen adresleri anlamlandıramadı. Daha anlamlı bir çıktı için şöyle bir çağrı yapabiliriz:
drepper$ mtrace tst errlog
- 0x08064cc8 Free 2 was never alloc'd /home/drepper/tst.c:39
- 0x08064ce0 Free 3 was never alloc'd /home/drepper/tst.c:39
- 0x08064cf8 Free 4 was never alloc'd /home/drepper/tst.c:39

Memory not freed:
-----------------
   Address     Size     Caller
0x08064c48     0x14  at /home/drepper/tst.c:33
0x08064c60     0x14  at /home/drepper/tst.c:33
0x08064c78     0x14  at /home/drepper/tst.c:33
0x08064c90     0x14  at /home/drepper/tst.c:33
Ansızın, çıktı daha ayrıntılı oluverdi. Yazılımcı artık hangi işlev çağrısının bozukluğa sebep olduğunu hemen görebilir.
Bu çıktının yorumlanması karmaşık değildir. En fazla iki farklı durum saptanmıştır. İlkinde, ayırma işlevlerinden döndürülmemiş göstericiler için free çağrılmış. Bu genelde çok kötü bir sorundur ve çıktının ilk üç satırında benzer bir durum gösterilmiştir. Bu gibi durumlar az görülür, çünkü sorun kendini çok dramatik olarak gösterir: yazılım normal olarak çöker.
Diğer durum saptanması daha zor olan bellek artıklarıdır. Çıktıda gördüğünüz gibi mtrace işlevi tüm bu bilgiyi toplamıştır. Bu çıktıya bakarak şunu söyleyebiliriz: yazılım /home/drepper/tst-mtrace.c kaynak dosyasının 33. satırındaki bir ayırma işlevini dört kere çağırmış ve yazılım sonlandırılmadan önce bu bellek serbest bırakılmamış. Acaba bu araştırılmayı bekleyen gerçek bir sorun mudur?
Önceki Üst Ana Başlık Sonraki
Özgür Bellek Ayırma Başlangıç Yığınaklar (Obstacks)
Bir Linux Kitaplığı Sayfası