Bir C uygulamasından çıktığınızda, malloc-ed bellek otomatik olarak serbest bırakılır mı?


97

Diyelim ki aşağıdaki C koduna sahibim:

int main () {
  int *p = malloc(10 * sizeof *p);
  *p = 42;
  return 0;  //Exiting without freeing the allocated memory
}

Bu C programını derlediğimde ve çalıştırdığımda, yani bellekte bir miktar alan ayırdıktan sonra, uygulamadan çıktıktan ve işlem sona erdikten sonra ayırdığım bellek hala tahsis edilecek mi (yani temelde yer kaplayacak mı)?


9
Belleğinizi temizlemenin "iyi bir tarzı", korumalı belleği olmayan bir işletim sistemi üzerinde çalışabileceğiniz için değil (aşağıdaki ana öneri), bellek sızıntıları bulma olasılığınızı artırdığı için kodunuz zayıf ve doğru ...
Matt Joiner

Yanıtlar:


116

İşletim sistemine bağlıdır. Modern (ve tüm büyük) işletim sistemlerinin çoğu, program bittiğinde program tarafından serbest bırakılmayan belleği boşaltacaktır.

Buna güvenmek kötü bir uygulamadır ve açıkça serbest bırakmak daha iyidir. Sorun yalnızca kodunuzun kötü görünmesi değildir. Küçük programınızı daha büyük, uzun soluklu bir programa entegre etmeye karar verebilirsiniz. Sonra bir süre sonra bellek sızıntılarını takip etmek için saatler harcamanız gerekir.
Bir işletim sisteminin bir özelliğine güvenmek de kodu daha az taşınabilir hale getirir.


16
Win98 ile bir keresinde gömülü bir platformda karşılaştım ve bu deneyime dayanarak, programlar kapandığında hafızayı boşaltmadığını söyleyebilirim.
San Jacinto

9
@Ken Bir örnek oldu. Ayrıca, YAGNI ile özensiz kodlama arasında bir çizgi var. Kaynakları serbest bırakmamak onu aşar. YAGNI ilkesinin, programın doğru çalışmasını sağlayan koda değil, özelliklere de uygulanması amaçlanmıştır. (Ve hafızayı boşaltmamak bir hatadır).
Yacoby

5
+1: Dikkate alınması gereken en önemli şey, bellek yönetiminin Yacoby'nin oldukça doğru bir şekilde ifade ettiği: "işletim sisteminin bir özelliği" olmasıdır . Yanılmıyorsam, programlama dili programın yürütülmesinden önce veya sonra ne olacağını tanımlamaz.
D.Shawley

9
Belleği manuel olarak boşaltmak daha fazla zaman alır, daha fazla kod gerektirir ve hata olasılığını ortaya çıkarır (serbest bırakma kodunda hiç hata görmediğini söyle!). Özel kullanım durumunuz için her yönden daha kötü olan bir şeyi kasıtlı olarak çıkarmak "özensiz" değildir. İşlem sonlandırıldıktan sonra sayfaları serbest bırakamayan veya onu daha büyük bir programa (YAGNI) entegre edemeyen eski / küçük bir sistemde çalıştırmak istemedikçe veya yapmadıkça, bana net bir kayıp gibi görünüyor. Kendini temizlememeyi düşünmenin bir programcının egosuna zarar verdiğini biliyorum, ama aslında hangi pratik açıdan daha iyi?
Ken

6
SO'da bellek sızıntıları öneren herkes tüm itibar ve rozetlerden sıyrılmalıdır
Ulterior

53

Genel olarak, modern genel amaçlı işletim sistemleri, sonlandırılan işlemlerden sonra temizlik yapar . Bu gereklidir, çünkü sistemin alternatifi, kötü yazılmış veya nadiren ortaya çıkan ve kaynakları sızdıran hatalar içeren programlar nedeniyle sistemin zaman içinde kaynaklarını kaybetmesi ve yeniden başlatmayı gerektirmesidir.

Programınızın kaynaklarını açıkça serbest bırakması, aşağıdakiler gibi çeşitli nedenlerle iyi bir uygulama olabilir :

  • Eğer ek kaynaklar varsa değil böyle geçici dosyaları veya herhangi bir tür olarak Çıkışta işletim sistemi tarafından temizlenir, değişim harici kaynağın durumuna, o zaman bu Çıkışta tüm bu şeyler ile uğraşmak kodu gerekir ve edecektir genellikle hafızayı boşaltmakla zarif bir şekilde birleştirilir.
  • Programınız daha uzun bir kullanım ömrüne sahip olmaya başlarsa, belleği boşaltmanın tek yolunun çıkmak olmasını istemeyeceksiniz . Örneğin, programınızı tek tek çalışma birimleri için birçok isteği işlerken çalışmaya devam eden bir sunucuya (arka plan programı) dönüştürmek isteyebilirsiniz veya programınız daha büyük bir programın küçük bir parçası olabilir.

Bununla birlikte, hafızayı boşaltmayı atlamanın bir nedeni var: verimli kapatma . Örneğin, uygulamanızın bellekte büyük bir önbellek içerdiğini varsayalım. Çıktığı zaman tüm önbellek yapısını gözden geçirir ve her seferinde bir parça serbest bırakırsa, bu hiçbir işe yaramaz ve kaynakları boşa harcar. Özellikle, önbelleğinizi içeren bellek sayfalarının işletim sistemi tarafından diske değiştirildiği durumu düşünün; yapıyı gezdirerek ve serbest bırakarak, tüm bu sayfaları bir kerede belleğe geri getiriyor , gerçek bir fayda sağlamak için önemli ölçüde zaman ve enerji harcıyorsunuz ve hatta muhtemelen sistemdeki diğer programların değiştirilmesine neden oluyorsunuz !

İlgili bir örnek olarak, her istek için bir işlem oluşturarak ve ardından tamamlandığında çıkışını sağlayarak çalışan yüksek performanslı sunucular vardır; bu sayede bellek tahsisini izlemek zorunda bile kalmazlar ve hiçbir zaman herhangi bir boşaltma veya çöp toplama işlemi yapmazlar, çünkü işlemin sonunda her şey işletim sisteminin boş belleğine geri döner. (Aynı tür bir işlem, özel bir bellek ayırıcı kullanılarak bir süreç içinde yapılabilir, ancak çok dikkatli bir programlama gerektirir; esasen işletim sistemi sürecinde kişinin kendi "hafif süreçler" kavramını oluşturması.)


11

Bu konuya son gönderiden çok sonra gönderdiğiniz için özür dilerim.

Ek bir nokta. Tüm programlar zarif çıkışlara ulaşamaz. Çökmeler ve ctrl-C'ler vb. Bir programın kontrolsüz yollarla çıkmasına neden olur. İşletim sisteminiz yığınınızı serbest bırakmadıysa, yığınızı temizlemediyse, statik değişkenleri silmediyse, sonunda sisteminizi bellek sızıntılarından veya daha kötüsünden kilitlersiniz.

Bunun dışında ilginç bir şey, Ubuntu'da çökmeler / kesintiler ve diğer tüm modern işletim sistemlerinden şüpheleniyorum, "işlenen" kaynaklarla ilgili sorunlar var. Soketler, dosyalar, cihazlar vb. Bir program bittiğinde / çöktüğünde "açık" kalabilir. Ayrıca, zarif bir şekilde çıkmadan önce temizlemenizin bir parçası olarak bir "tutamaç" veya "tanımlayıcı" ile her şeyi kapatmak için iyi bir uygulama.

Şu anda yoğun şekilde soket kullanan bir program geliştiriyorum. Bir askıda kaldığımda, ctrl-c'yi ondan çıkarmam gerekiyor, böylece soketlerimi büküyorum. Tüm açık soketlerin bir listesini toplamak için bir std :: vektör ve sigint ve sigterm'i yakalayan bir sigaction işleyicisi ekledim. İşleyici listeyi yürütür ve yuvaları kapatır. Atışlardan önce, erken sonlandırmaya yol açacak benzer bir temizleme rutini yapmayı planlıyorum.

Bu tasarım hakkında yorum yapmak isteyen var mı?


1
Bunu söylediğinize sevindim, çünkü soket kaynaklarını etrafta bırakan bir programım vardı ve Ubuntu sistemimizin her iki haftada bir yeniden başlatılması gerekiyordu veya bellek tükenmeye başladı ve bol miktarda bellek var. Temizlemeyi unutursanız, sistem kaynaklarının bozulacağından emin değilim.
octopusgrabbus

8
Stackoverflow bir forum değildir; orada hiçbir şey eski soruya cevap yanlış. meta.stackexchange.com/questions/20524/reviving-old-questions
mk12

6

Burada ( modern bir işletim sisteminde ) olan şey, programınızın kendi "süreci" içinde çalışmasıdır. Bu, kendi adres alanı, dosya tanımlayıcıları, vb. İle donatılmış bir işletim sistemi varlığıdır. mallocÇağrılarınız, "yığın" dan veya işleminize atanan ayrılmamış bellek sayfalarından bellek ayırıyor.

Programınız sona erdiğinde, bu örnekte olduğu gibi, işleminize atanan tüm kaynaklar işletim sistemi tarafından basitçe geri dönüştürülür / parçalanır. Bellek durumunda, size atanmış tüm bellek sayfaları basitçe "boş" olarak işaretlenir ve diğer işlemlerin kullanımı için geri dönüştürülür. Sayfalar, malloc'un işlediğinden daha düşük seviyeli bir kavramdır - sonuç olarak, malloc / free'nin özellikleri, her şey temizlenirken basitçe silinir.

Bu ahlaki eşdeğeri, dizüstü bilgisayarınızı kullanmayı bitirdiğinizde ve bir arkadaşınıza vermek istediğinizde, her dosyayı ayrı ayrı silmeye zahmet etmeyin. Siz sadece sabit sürücüyü biçimlendirin.

Bütün bunlar, diğer tüm cevaplayıcıların da belirttiği gibi, buna güvenmenin iyi bir uygulama olmadığını söyledi:

  1. Her zaman kaynaklara dikkat etmek için programlama yapmalısınız ve bu C de hafıza anlamına gelir. Sonunda kodunuzu bir kitaplığa yerleştirebilirsiniz veya beklediğinizden çok daha uzun süre çalışmaya başlayabilir.
  2. Bazı işletim sistemleri (eski işletim sistemleri ve belki bazı modern gömülü işletim sistemleri) bu kadar katı süreç sınırlarını koruyamayabilir ve ayırmalarınız başkalarının adres alanlarını etkileyebilir.

4

Evet. İşletim sistemi kaynakları temizler. Şey ... NetWare'in eski sürümleri yoktu.

Düzenleme: San Jacinto'nun işaret ettiği gibi, kesinlikle bunu yapmayan sistemler (NetWare dışında) var. Atma programlarında bile, sırf alışkanlığı sürdürmek için tüm kaynakları serbest bırakmayı alışkanlık haline getirmeye çalışıyorum.


3
Olumsuz oy kullanmıyorum, ama bu gelecek kuşaklar için oldukça tehlikeli bir gönderi. DOS hala birçok gömülü platformda kullanılıyor ve bellek temizliğini sizin için yaptığından CİDDİ şüpheliyim. Kapsamlı genelleme yanlış.
San Jacinto

@San Jacinto: Bu iyi bir nokta. Bu yüzden NetWare referansı yaptım, ancak muhtemelen açıklama gerektirebilir. Biraz düzenleyeceğim.
Mark Wilkins

3
@San DOS, çok görevli bir işletim sistemi değildir - bir DOS programı (TSR'ler hariç) sona erdiğinde, tüm bellek yüklenecek sonraki program için kullanılabilir.

@Neil hatırlatıcı için teşekkürler, ancak gömülü sistemler için yaygın bir kullanım olduğu gibi bir olay meydana geldiğinde başlatılacak TSR benzeri bir programdan bahsediyordum. Yine de, nerede başarısız olduğum için uzmanlığınız ve açıklamanız için teşekkür ederim :)
San Jacinto

2

Evet, işletim sistemi işlem bittiğinde tüm belleği serbest bırakır.


Bunun neden reddedildiğini anlamıyorum. süreç öldüğünde malloc'ed bellek serbest bırakılacak (malloc'un wikipedia tanımı öyle söylüyor)
Arve

7
Wikipedia, var olan her işletim sistemi için bir kılavuz değildir. Çoğu modern işletim sistemi hafızayı geri kazanacaktır, ancak hepsi değil (ve özellikle de hepsi değil). Buna ek olarak, mallocsadece C'nin hafıza ile ne yapacağına söz verebilir; C, tasarım gereği, C'nin dışındaki davranışlarla ilgili pek bir şey garanti etmez. Uygulama beklenmedik bir şekilde ölürse, çalışma zamanı kitaplığının verdiği sözler geçersiz ve geçersizdir, çünkü artık onlara uyacak şekilde hayatta değildir.
cHao

2

Değişir, işletim sistemleri bunu sizin için genellikle temizler, ancak örneğin gömülü yazılım üzerinde çalışıyorsanız, o zaman piyasaya sürülmeyebilir.

Sadece serbest bıraktığınızdan emin olun, daha sonra büyük bir projeye entegre etmek isteyebileceğiniz zaman size çok zaman kazandırabilir.


0

Bu gerçekten işletim sistemine bağlıdır, ancak karşılaşacağınız tüm işletim sistemleri için, işlemden çıkıldığında bellek tahsisi kaybolacaktır.


0

Doğrudan serbest bırakmanın en iyisi olduğunu düşünüyorum. Tanımlanmamış davranış en kötü şeydir, bu yüzden hala sürecinizde tanımlıyken erişiminiz varsa, yapın, insanların bunun için vermiş olduğu birçok iyi neden vardır.

Nerede ya da olup olmadığına gelince, bunu W98'de buldum, asıl soru 'ne zaman' idi (bunu vurgulayan bir gönderi görmedim). Küçük bir şablon programı (MIDI SysEx girişi için, çeşitli malloc'lu boşlukları kullanarak) WndProc'un WM_DESTROY bitinde belleği boşaltacaktı, ancak bunu daha büyük bir programa aktardığımda çıkışta çöktü. Bunun, daha büyük bir temizlik sırasında işletim sisteminin serbest bıraktığı şeyi serbest bırakmaya çalıştığım anlamına geldiğini varsaydım. Bunu WM_CLOSE'de yapıp DestroyWindow () olarak adlandırırsam, hepsi iyi çalıştı, anında temiz çıktı.

Bu MIDI arabellekleri ile tam olarak aynı olmasa da, işlemi sağlam tutmak, tamamen temizlemek ve sonra çıkmak en iyisidir. Mütevazı bellek parçalarıyla bu çok hızlıdır. Birçok küçük arabellek işleminde ve temizlemede daha az sayıda büyük arabelleğe göre daha hızlı çalıştığını buldum.

Birisinin büyük bellek parçalarını diskteki bir takas dosyasından geri çekmekten kaçındığını söylediği gibi istisnalar olabilir, ancak bu bile daha fazla ve daha küçük, ayrılmış alan tutularak en aza indirilebilir.

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.