Malloc'dan sonra serbest kalmadığınızda GERÇEKTEN ne olur?


538

Bu, uzun zamandır beni rahatsız eden bir şey oldu.

Hepimize okulda (en azından ben) tahsis edilen her işaretçiyi serbest bırakmanız GEREKİR. Yine de, hafızayı boşaltmamanın gerçek maliyeti hakkında biraz merak ediyorum. Bazı açık durumlarda, mallocbir döngü içinde veya bir iş parçacığı yürütmesinin bir parçası olarak çağrıldığında olduğu gibi, serbest bırakmak çok önemlidir, bu nedenle bellek sızıntısı olmaz. Ancak aşağıdaki iki örneği göz önünde bulundurun:

İlk olarak, ben böyle bir şey kodu varsa:

int main()
{
    char *a = malloc(1024);
    /* Do some arbitrary stuff with 'a' (no alloc functions) */
    return 0;
}

Buradaki gerçek sonuç nedir? Benim düşüncem, sürecin öldüğü ve daha sonra yığın alanının yine de gittiğinden, çağrıyı kaçırmanın hiçbir zararı yoktur free(ancak, kapatma, sürdürülebilirlik ve iyi uygulama için yine de sahip olmanın önemini biliyorum). Bu düşüncede haklı mıyım?

İkinci olarak, biraz kabuk gibi davranan bir programım olduğunu varsayalım. Kullanıcılar gibi değişkenler bildirebilir aaa = 123ve bunlar daha sonra kullanılmak üzere bazı dinamik veri yapısında saklanır. Açıkçası, bazı * tahsis işlevi (hashmap, bağlantılı liste, bunun gibi bir şey) çağıracak bir çözüm kullanacağınız açıktır. Bu tür bir program için, çağrıldıktan sonra hiçbir zaman özgür olmanız mantıklı değildir mallocçünkü bu değişkenler programın yürütülmesi sırasında her zaman mevcut olmalıdır ve bunu statik olarak ayrılmış alanla uygulamanın iyi bir yolu yoktur (görebiliyorum). Tahsis edilen ancak yalnızca işlemin sona eren bir parçası olarak boşaltılan bir grup belleğe sahip olmak kötü bir tasarım mıdır? Eğer öyleyse, alternatif nedir?


7
@NTDLS Derecelendirme sisteminin büyüsü aslında bir kez çalışıyor: 6 yıl sonra ve "daha haklı" cevap gerçekten zirveye çıktı.
zxq9

15
Aşağıdaki kişiler iyi bir modern işletim sisteminin temizlik yaptığını söylemeye devam ediyor, ancak kod çekirdek modunda çalışıyorsa (örneğin, performans nedenleriyle)? Çekirdek modu programları (örneğin Linux'ta) korumalı mı? Değilse, sanırım abort () gibi anormal sonlandırmalardan önce bile her şeyi manuel olarak serbest bırakmanız gerekir.
Dr. Kişi Kişi II

3
@ Dr.PersonPersonII Evet, çekirdek modunda çalışan kod genellikle her şeyi manuel olarak serbest bırakmak zorundadır.
zwol

1
Bu free(a)aslında gerçekten boş hafıza için hiçbir şey yapmaz eklemek istiyorum ! Yalnızca, büyük bir mmapped bellek sayfası (genellikle "yığın" olarak adlandırılır) içindeki kullanılabilir bellek parçalarını takip eden malloc'un libc uygulamasındaki bazı işaretçileri sıfırlar. Bu sayfa daha önce değil, yalnızca programınız sona erdiğinde serbest bırakılacaktır.
Marco Bonelli

1
Free () aslında belleği serbest bırakabilir veya bırakmayabilir. Yalnızca bloğu serbest bırakılmış, daha sonra geri alınacak şekilde işaretleyebilir veya ücretsiz bir listeye bağlayabilir. Onu bitişikteki serbest bloklarla birleştirebilir veya daha sonraki bir tahsis için bunu bırakabilir. Hepsi bir uygulama detayı.
Jordan Brown

Yanıtlar:


378

Hemen hemen her modern işletim sistemi, bir program çıktıktan sonra ayrılan tüm bellek alanını kurtaracaktır. Düşünebildiğim tek istisna, programın statik depolama ve çalışma zamanı belleğinin hemen hemen aynı şey olduğu Palm OS gibi bir şey olabilir, bu nedenle serbest bırakmamak, programın daha fazla depolama alanı kaplamasına neden olabilir. (Ben sadece burada spekülasyon yapıyorum.)

Bu nedenle, genellikle, ihtiyacınız olandan daha fazla depolama alanına sahip çalışma zamanı maliyeti dışında herhangi bir zararı yoktur. Kesinlikle verdiğiniz örnekte, temizlenene kadar kullanılabilecek bir değişkenin belleğini saklamak istersiniz.

Ancak, daha fazla ihtiyacınız olmadığı anda belleği boşaltmak ve program çıkışında hala sahip olduğunuz her şeyi boşaltmak iyi bir stil olarak kabul edilir. Bu daha çok hangi belleği kullandığınızı bilmek ve hala ihtiyacınız olup olmadığını düşünmek için yapılan bir alıştırmadır. Takipte bulunmazsanız, bellek sızıntılarınız olabilir.

Öte yandan, çıkışta dosyalarınızı kapatmak için kullanılan benzer uyarının çok daha somut bir sonucu vardır - eğer yapmazsanız, onlara yazdığınız veriler temizlenmeyebilir veya geçici bir dosyaysa, işiniz bittiğinde silinir. Ayrıca, veritabanı tanıtıcıları işlemlerini tamamlamış ve işiniz bittiğinde kapatılmış olmalıdır. Benzer şekilde, C ++ veya Objective C gibi bir nesne yönelimli dil kullanıyorsanız, bir nesneyi bitirdiğinizde serbest bırakmak yıkıcıya hiçbir zaman çağrılamaz ve sınıfın sorumlu olduğu herhangi bir kaynak temizlenmeyebilir.


16
Muhtemelen herkesin modern bir işletim sistemi kullanmadığını belirtmek iyi olur, eğer birisi programınızı alırsa (ve hala belleği kurtarmayan bir işletim sisteminde çalışıyorsa) GG'yi çalıştırır.
user105033

79
Bu yanıtı yanlış düşünüyorum. Biri onlarla yapıldıktan sonra her zaman kaynakları ele almalı, dosya tanıtıcıları / bellek / muteksler olsun. Bu alışkanlığa sahip olarak, sunucular oluşturulurken böyle bir hata yapılmaz. Bazı sunucuların 7 gün 24 saat çalışması bekleniyor. Bu gibi durumlarda, herhangi bir türden sızıntı, sunucunuzun sonunda bu kaynaktan tükeneceği ve bir şekilde askıda kalacağı / çökeceği anlamına gelir. Kısa bir yardımcı program, bir sızıntı o kadar da kötü değil. Herhangi bir sunucu, herhangi bir sızıntı ölümdür. Kendine bir iyilik yap. Kendinizi temizleyin. Bu iyi bir alışkanlık.
EvilTeach

120
"Ancak, artık ihtiyacınız olmadığı anda belleği boşaltmak ve program çıkışında hala sahip olduğunuz her şeyi boşaltmak iyi bir stil olarak kabul edilir." yanlış mı düşünüyorsun?
Paul Tomblin

24
Programın çıktığı ana kadar ihtiyacınız olan bir bellek deponuz varsa ve ilkel bir işletim sisteminde çalışmıyorsanız, çıkmadan hemen önce belleği boşaltmak bir kusur değil, stilistik bir seçimdir.
Paul Tomblin

30
@Paul - EvilTeach ile aynı fikirde olmak, hafızayı boşaltmak için iyi bir stil olarak kabul edilmez, hafızayı boşaltmamak yanlıştır. İfadeleriniz, kravatınızla eşleşen bir mendil giymek kadar önemli görünmesini sağlar. Aslında, pantolon giyme seviyesinde.
Heath Hunnicutt

110

Evet haklısınız, örneğin hiçbir zararı yok (en azından çoğu modern işletim sisteminde). İşleminiz için ayrılan tüm bellek, işlemden çıktıktan sonra işletim sistemi tarafından kurtarılır.

Kaynak: Tahsis ve GC Efsaneleri (PostScript uyarısı!)

Tahsis Efsanesi 4: Çöp toplanmamış programlar her zaman ayırdıkları tüm belleği ayırmalıdır.

Gerçek: Sık çalıştırılan kodda atlanan serbest bırakmalar artan sızıntılara neden olur. Nadiren kabul edilebilir. ancak program çıkışına kadar en çok ayrılan belleği koruyan Programlar, müdahale eden herhangi bir ayırma olmadan genellikle daha iyi performans gösterir. Malloc'un ücretsiz olmaması durumunda uygulanması çok daha kolaydır.

Çoğu durumda, program çıkışından hemen önce bellek yeniden yerleştirmek anlamsızdır. İşletim sistemi yine de geri alacak. Ücretsiz ölü nesnelere dokunacak ve sayfa olacak; İşletim sistemi olmayacak.

Sonuç: Tahsisleri sayan "kaçak detektörlerine" dikkat edin. Bazı "sızıntılar" iyidir!

Bununla birlikte, tüm bellek sızıntılarından kaçınmaya çalışmalısınız!

İkinci soru: tasarımınız tamam. Uygulamanız çıkana kadar bir şey depolamanız gerekiyorsa, bunu dinamik bellek ayırma ile yapmak uygun olur. Gerekli boyutu önceden bilmiyorsanız, statik olarak ayrılan belleği kullanamazsınız.


3
Olabilir, çünkü soru, okuduğum gibi, bu spesifik örneğin iyi olup olmadığı değil, sızan hafızaya gerçekte olan şeydir. Yine de oy kullanmam, çünkü bu hala iyi bir cevap.
DevinB

3
Muhtemelen (erken Windows, erken Mac OS) vardı ve belki de hala, çıkıştan önce belleği boşaltmak için işlem gerektiren işletim sistemleri, aksi takdirde alan geri kazanılmaz.
Pete Kirkham

Bellek parçalanması veya belleğin bitmesi umurumda değilse, tamamdır - bunu çok fazla yaparsınız ve uygulamalarınızın performansı kaybolur. Zor gerçeklerin yanı sıra, her zaman en iyi uygulamaları ve iyi alışkanlık geliştirmeyi takip edin.
NTDLS

1
Şu anda -11 civarında oturan kabul edilmiş bir cevabım var, bu yüzden kayıt için koşmuyor bile.
Paul Tomblin

8
Sanırım "(kaçak detektörü nedeniyle)" diyerek hafızayı serbest bırakmanın gerekliliğini açıklamanın yanlış olduğunu düşünüyorum. Bu demek oluyor ki "bir oyun sokakta yavaş sürmek zorundasınız çünkü polis adamları bir hız kamerası ile sizi bekliyor olabilir".
Sebastian Mach

57

=== Gelecekteki yazım denetimleri ve kodun yeniden kullanımı ne olacak ? ===

Eğer varsa yok nesneleri serbest kod yazmak size kapatılıyor işlemle free'd ediliyor belleğe ... yani küçük tek kullanımlık bağlı olabilir zaman, o zaman sadece güvenli olması için kod sınırlandırıyor kullanmak projeler veya "fırlatma" [1] projeleri) ... sürecin ne zaman sona ereceğini bilirsiniz.

Eğer varsa yapmak () tüm dinamik olarak ayrılan bellek s ücretsiz, o zaman gelecek kodunu geçirmezlik ve icar olduğunu kod yazmak diğerleri daha büyük bir projede kullanmak.


[1] “fırlatma” projeleri ile ilgili. "Throw-away" projelerinde kullanılan kodun atılmamak için bir yolu vardır. On yıl geçtiğini bildiğiniz ve attığınız "kodunuz hala kullanılıyor).

Donanımının daha iyi çalışmasını sağlamak için sadece eğlence için kod yazan bir adam hakkında bir hikaye duydum. " Sadece bir hobi, büyük ve profesyonel olmayacak " dedi. Yıllar sonra birçok kişi "hobi" kodunu kullanıyor.


8
"Küçük projeler" için indirildi. Çıkışta çok fazla kasıtlı olarak bellekte boş alan olmayan birçok büyük proje var, çünkü hedef platformlarınızı biliyorsanız zaman kaybı. IMO, daha doğru bir örnek "yalıtılmış projeler" olurdu. Örneğin, diğer uygulamalara eklenecek yeniden kullanılabilir bir kitaplık oluşturuyorsanız, iyi tanımlanmış bir çıkış noktası yoktur, bu nedenle bellek sızdırmazsınız. Bağımsız bir uygulama için, işlemin ne zaman sona erdiğini her zaman tam olarak bileceksiniz ve temizlemeyi işletim sistemine boşaltmak için bilinçli bir karar verebilirsiniz (bu, her iki şekilde de yapılması gerekir).
Dan Bechard

Dünün uygulaması bugünün kütüphane işlevidir ve yarın binlerce kez çağıran uzun ömürlü bir sunucuya bağlanacaktır.
Adrian McCarthy

1
@AdrianMcCarthy: Bir işlev statik bir işaretçinin boş olup olmadığını kontrol malloc()ederse, ile işaretler ve işaretçi hala boşsa sonlandırılırsa, böyle bir işlev freehiçbir zaman çağrılmasa bile güvenli bir şekilde defalarca kullanılabilir . Sınırsız miktarda depolama alanı kullanabilen bellek sızıntılarını, yalnızca sınırlı ve öngörülebilir bir depolama alanını boşa harcayan durumlara göre ayırmanın faydalı olacağını düşünüyorum.
supercat

@supercat: Yorumum kodun zaman içinde değişmesinden bahsediyordu. Tabii, sınırlı miktarda bellek sızıntısı sorun değil. Ama bir gün, birisi bu işlevi değiştirmek isteyecek, böylece artık statik bir işaretçi kullanmıyor. Kodun sivri belleği serbest bırakması için herhangi bir hükmü yoksa, bu zor bir değişiklik olacaktır (veya daha da kötüsü, değişiklik kötü olacaktır ve sınırsız bir sızıntı ile sonuçlanacaksınız).
Adrian McCarthy

1
@AdrianMcCarthy: Artık statik bir işaretçi kullanmamak için kodun değiştirilmesi, işaretçiyi bir tür "bağlam" nesnesine taşımayı ve bu tür nesneleri oluşturmak ve yok etmek için kod eklemeyi gerektirecektir. İşaretçi her zaman nullayırma yoksa ve ayırma olduğunda boş değilse, kodun ayırmayı serbest bırakması ve işaretçiyi nullbir bağlam yok edildiğinde işaretleyiciye ayarlamanız , özellikle yapılması gereken diğer her şeyle karşılaştırıldığında, basit olacaktır. statik nesneleri bir bağlam yapısına taşımak için.
supercat

52

Haklısın, zararı yok ve sadece çıkmak daha hızlı

Bunun farklı nedenleri var:

  • Tüm masaüstü ve sunucu ortamları çıkışta bellek alanının tamamını serbest bırakır (). Yığınlar gibi program-dahili veri yapılarının farkında değildirler.

  • Hemen hemen tüm free()uygulamalar şimdiye yok zaten işletim sistemine bellek dönün.

  • Daha da önemlisi, çıkıştan () hemen önce yapıldığında zaman kaybıdır. Çıkışta bellek sayfaları ve takas alanı serbest bırakılır. Buna karşılık, bir dizi ücretsiz () çağrı CPU zamanını yakar ve disk sayfalama işlemlerine, önbellek kayıplarına ve önbellek boşaltımlarına neden olabilir.

İlgili Possiblility justifing yeniden gelecek kodunun kesinlik anlamsız ops: Bir göz ama o tartışmalı değil Çevik yol. YAGNI!


2
Bir zamanlar bir programın bellek kullanımını anlamaya çalışmak için kısa bir süre harcadığımız bir proje üzerinde çalıştım (desteklememiz gerekiyordu, yazmadık). Deneyime dayanarak ikinci merminize anekdot olarak katılıyorum. Ancak, bunun (veya birisinin) bunun doğru olduğuna dair daha fazla kanıt sağladığını duymak isterim.
user106740

3
Boş ver, cevabı buldu: stackoverflow.com/questions/1421491/… . Çok teşekkürler!
user106740

@aviggiano YAGNI denir.
v.oddou

YAGNI prensibi her iki şekilde de çalışır: Kapatma yolunu asla optimize etmeniz gerekmez. Erken optimizasyonlar ve tüm bunlar.
Adrian McCarthy

26

OP'nin doğru olduğunu veya zarar olmadığını söyleyen herkese tamamen katılmıyorum.

Herkes modern ve / veya eski bir işletim sisteminden bahsediyor.

Ama ya hiç işletim sistemimin olmadığı bir ortamdaysam? Nerede hiçbir şey yok?

Şimdi iş parçacığı tarzı kesmeler kullandığınızı ve bellek ayırdığınızı düşünün. C standardında ISO / IEC: 9899, ​​şu şekilde belirtilen bellek ömrüdür:

7.20.3 Bellek yönetimi işlevleri

1 Calloc, malloc ve realloc işlevlerine art arda yapılan çağrılarla ayrılan depolama sırası ve bitişikliği belirtilmemiş. Ayırma başarılı olursa döndürülen işaretçi, herhangi bir nesne türüne bir işaretçiye atanabilmesi için uygun şekilde hizalanır ve daha sonra, ayrılan alanda bu tür bir nesneye veya bu tür nesnelerden oluşan bir diziye (boşluk açıkça yeniden yerleşinceye kadar) erişmek için kullanılır. . Tahsis edilen bir nesnenin ömrü, tahsisattan ayırmaya kadar uzanır. [...]

Bu yüzden çevrenin sizin için serbest işi yaptığı belirtilmemelidir. Aksi takdirde son cümleye eklenir: "Veya program sona erene kadar."

Başka bir deyişle: Belleği boşaltmak sadece kötü bir uygulama değildir. Taşınabilir olmayan ve C uygun olmayan kod üretir. Hangisi en azından 'doğru ise, şu şekilde görülebilir: [...], çevre tarafından desteklenir'.

Ancak hiç işletim sisteminizin olmadığı durumlarda, kimse sizin için işi yapmaz (genellikle gömülü sistemlere bellek ayırmadığınızı ve yeniden tahsis etmediğinizi biliyorum, ancak isteyebileceğiniz durumlar vardır.)

Yani genel düz olarak (OP'nin etiketlendiği) konuşmak gerekirse, bu sadece hatalı ve taşınabilir olmayan kod üretmektedir.


4
Karşı argüman, gömülü bir ortam olmanız durumunda, geliştirici olarak, öncelikle bellek yönetiminizde çok daha titiz olacağınızdır. Genellikle bu, herhangi bir çalışma zamanı mallokuna / reallokuna sahip olmak yerine önceden statik sabit belleği önceden ayırma noktasına gelir.
John Go-Soco

1
@lunarplasma: Söyledikleriniz yanlış olmasa da, bu, standartların söylediklerini değiştirmez ve buna karşı / daha ileri davranan herkes, sağduysa bile, sınırlı kod üretir. Bazılarının "umursamam gerekmiyor" dediklerini anlayabiliyorum, çünkü yeterince iyi durumlar var. AMA en azından NEDEN umurunda olmak zorunda olmadığını bilmek gerekir. ve özellikle bir soru bu özel durumla ilgili olmadığı sürece bunu atlamamaktadır. Ve OP genel olarak teorik (okul) açılardan C'yi soruyor. "Gerek yok" demek doğru değil!
dhein

2
İşletim sisteminin olmadığı ortamların çoğunda, programların "sonlandırılabileceği" hiçbir yol yoktur.
supercat

@supercat: Daha önce yazdığım gibi: Haklısın. Ama eğer birisi öğretim nedenleri ve okul yönleri ile ilgili olarak bunu soruyorsa, "çoğu zaman önemli olmadığını düşünmek zorunda değilsiniz" dilini söylemek doğru değildir. tanım bir sebeple verilir ve çoğu çevre bunu sizin için hallettiği için, ilgilenmenize gerek olmadığını söyleyemezsiniz. Demek istediğim bu.
dhein

2
Çoğu standart bir işletim sistemi yokken geçerli DEĞİLDİR, özellikle de bellek yönetimi ve standart kütüphane işlevleri ile ilgili özellikler sağlamak için hiçbir çalışma zamanı olmadığından C standardını alıntılamak için -1 çalışma zamanı / OS ile birlikte).

23

İşimi bitirdiğimden emin olduktan sonra genellikle tahsis edilen her bloğu serbest bırakırım. Bugün, programımın giriş noktası olabilir main(int argc, char *argv[]), ancak yarın foo_entry_point(char **args, struct foo *f)bir işlev işaretçisi olarak yazılabilir.

Bu durumda, şimdi bir sızıntı var.

İkinci sorunuzla ilgili olarak, programım a = 5 gibi girdi alırsa, a için alan ayırır veya sonraki a = "foo" için aynı alanı yeniden ayırırdım. Bu, şu tarihe kadar tahsis edilecektir:

  1. Kullanıcı 'unset a' yazdı
  2. Temizleme işlevim girildi, bir sinyale hizmet verdi veya kullanıcı 'quit' yazdı

Bir işlemden sonra belleği geri almayan herhangi bir modern işletim sistemini düşünemiyorum . Sonra tekrar, free () ucuz, neden temizlemiyorsun? Diğerlerinin söylediği gibi, valgrind gibi araçlar gerçekten endişelenmeniz gereken sızıntıları tespit etmek için mükemmeldir. Örneklediğiniz bloklar 'yine de ulaşılabilir' olarak etiketlense de, sızıntı olmadığından emin olmaya çalışırken çıkıştaki ekstra gürültü.

Başka bir efsane " onun main (), ben özgür zorunda değilim ", bu yanlış. Aşağıdakileri göz önünde bulundur:

char *t;

for (i=0; i < 255; i++) {
    t = strdup(foo->name);
    let_strtok_eat_away_at(t);
}

Bu, çatallama / arka plandan çıkarma (ve teoride sonsuza kadar çalışan) öncesinde geldiyse, programınız henüz belirlenmemiş bir boyutta 255 kez sızdırılmıştı.

İyi, iyi yazılmış bir program her zaman kendi kendini temizlemelidir. Tüm dosyaları boşaltın, tüm dosyaları temizleyin, tüm tanımlayıcıları kapatın, tüm geçici dosyaların bağlantısını kesin, vb. bir çökme algıla ve devam et.

Gerçekten, başka şeylere geçtiğinizde eşyalarınızı korumak zorunda olan fakir ruha karşı nazik olun .. onlara 'valgrind clean' verin ... :)


1
Ve evet, bir defasında bir takım arkadaşı söyle vardı: <shudders> "Ben ana () içinde () serbest çağırmanız gerekir asla"
Tim Mesaj

free() is cheapbirer birer serbest bırakmanız gereken karmaşık bir ilişkiye sahip milyarlarca veri yapınız yoksa, her şeyi serbest bırakmak için veri yapısının üzerinden geçilmesi, özellikle de bu veri yapısının yarısı zaten sayfalanmışsa, kapatma sürenizi önemli ölçüde artırabilir. herhangi bir fayda olmadan diske.
Yalan Ryan

3
@LieRyan Bir milyarınız varsa, kelimenin tam anlamıyla bir milyar yapıda olduğu gibi, en önemlisi özel bir değerlendirme derecesine ihtiyaç duyan başka sorunlarınız var - bu özel cevabın kapsamının çok ötesinde :)
Tim Post

13

Çıktığınızda belleği serbest bırakmak tamamen iyidir; malloc (), belleği "yığın" adı verilen bellek alanından ayırır ve işlemden çıkıldığında bir işlemin tüm yığını serbest bırakılır.

Bununla birlikte, insanların çıkmadan önce her şeyi serbest bırakmanın iyi olmasının ısrar etmesinin bir nedeni, bellek hata ayıklayıcılarının (örneğin Linux'ta valgrind) serbest bırakılmamış blokları bellek sızıntısı olarak algılamasıdır ve ayrıca "gerçek" bellek sızıntıları varsa, sonunda "sahte" sonuçlar alırsanız onları tespit etmek daha zor.


1
Valgrind "sızdırılmış" ve "hala ulaşılabilir" arasında ayrım yapmakta iyi bir iş çıkarmıyor mu?
Christoffer

11
-1 "tamamen iyi" için Ayrılan belleği boşaltmadan bırakmak kötü kodlama uygulamasıdır. Bu kod bir kütüphaneye çıkarıldıysa, o yerde her yerde memleaks neden olur.
DevinB

5
Telafi etmek için +1. Bkz. freeEn exitzamanda zararlı düşündü.
R .. GitHub BUZA YARDIMCI DURDUR

11

Tahsis ettiğiniz belleği kullanıyorsanız, yanlış bir şey yapmazsınız. Belleği boşaltmadan ve programınızın geri kalanında kullanılabilir hale getirmeden ayıran işlevler (ana bilgisayar dışında) yazdığınızda bir sorun haline gelir. Ardından programınız kendisine ayrılan bellekle çalışmaya devam eder, ancak onu kullanmanın bir yolu yoktur. Programınız ve çalışan diğer programlar bu bellekten yoksun bırakılıyor.

Düzenleme: Diğer çalışan programların bu bellekten yoksun olduğunu söylemek% 100 doğru değildir. İşletim sistemi, programınızı sanal belleğe ( </handwaving>) dönüştürmek pahasına kullanmasına her zaman izin verebilir . Bununla birlikte, programınız kullanmadığı belleği serbest bırakırsa, sanal bellek takasının gerekli olma olasılığı daha düşüktür.


11

Bu kod genellikle iyi çalışır, ancak kodun yeniden kullanılması sorununu göz önünde bulundurun.

Ayrılmış belleği serbest bırakmayan bir kod snippet'i yazmış olabilirsiniz, böylece bellek daha sonra otomatik olarak geri kazanılacak şekilde çalıştırılır. Tamam görünüyor.

Daha sonra snippet'inizi saniyede bin kez yürütülecek şekilde projesine kopyalar. O kişinin programında artık büyük bir bellek sızıntısı var. Genel olarak çok iyi değil, genellikle bir sunucu uygulaması için ölümcül.

Kodların yeniden kullanımı işletmelerde tipiktir. Genellikle şirket çalışanlarının ürettiği tüm kodlara sahiptir ve her departman şirketin sahip olduğu her şeyi yeniden kullanabilir. Yani böyle "masum görünümlü" bir kod yazarak diğer insanlara potansiyel baş ağrısına neden oluyorsunuz. Bu seni kovabilir.


2
Parçacığı kopyalayan birinin değil, tekrar tekrar yapmak için değiştirildikten sonra belirli bir eylemi yapmak için yazılmış bir programın olasılığını da belirtmek gerekir. Böyle bir durumda, belleğin bir kez tahsis edilmesi ve daha sonra hiç serbest bırakılmadan tekrar tekrar kullanılması iyi olur, ancak belleği (serbest bırakmadan) her eylem için tahsis etmek ve bırakmak felaket olabilir.
supercat

7

Buradaki gerçek sonuç nedir?

Programınız belleği sızdırdı. İşletim sisteminize bağlı olarak kurtarılmış olabilir .

Çoğu modern masaüstü işletim sistemleri yapmak burada birçok diğer cevaplar ile görülebileceği gibi ne yazık ki yaygın sorunu görmezden yapım süreci bitiminde sızan belleği kurtarmak.)

Ama güvenmemelidir bir emniyet özelliği güveniyorlar, ve program (veya işlevi) bu davranış bir sistem üzerinde çalışabilir yapar bir "sert" bellek sızıntısı, sonucu bir sonraki sefer.

Çekirdek modunda veya bir bellek olarak bellek koruması kullanmayan eski / katıştırılmış işletim sistemlerinde çalışıyor olabilirsiniz. (MMU'lar kalıp alanı kaplar, bellek koruması ek CPU döngülerine mal olur ve bir programcıdan kendini temizlemesini istemek çok fazla değildir).

Belleği istediğiniz gibi kullanabilir ve yeniden kullanabilirsiniz, ancak çıkmadan önce tüm kaynakları ayırdığınızdan emin olun.


5

Aslında OSTEP çevrimiçi ders kitabında, işletim sistemlerinde bir lisans dersi için sorunuzu tam olarak tartışan bir bölüm var .

İlgili bölüm, aşağıdaki açıklamaları içeren sayfa 6'daki Bellek API'sı bölümünde "Belleği Boşaltmayı Unutmak" tır :

Bazı durumlarda, free () işlevini çağırmamak makul görünebilir. Örneğin, programınız kısa ömürlüdür ve yakında çıkacaktır; bu durumda, işlem sona erdiğinde, İşletim Sistemi tahsis edilen tüm sayfaları temizler ve böylece hiçbir bellek sızıntısı gerçekleşmez. Bu kesinlikle "işe yarar" olsa da (sayfa 7'deki kenara bakın), muhtemelen gelişmesi kötü bir alışkanlıktır, bu yüzden böyle bir strateji seçmeye dikkat edin

Bu alıntı, sanal bellek kavramını tanıma bağlamındadır. Temelde kitabın bu noktasında, yazarlar bir işletim sisteminin amaçlarından birinin "hafızayı sanallaştırmak" olduğunu, yani her programın çok büyük bir bellek adres alanına erişimi olduğuna inanmasını sağlamak olduğunu açıklar.

Sahne arkasında, işletim sistemi kullanıcının gördüğü "sanal adresleri" fiziksel belleğe işaret eden gerçek adreslere çevirecektir.

Ancak, fiziksel bellek gibi kaynakları paylaşmak, işletim sisteminin bu işlemi hangi işlemlerin kullandığını takip etmesini gerektirir. Bir işlem sona ererse, işlemin belleğini yeniden dağıtmak ve belleği diğer işlemlerle paylaşabilmesi için işletim sisteminin yetenekleri ve tasarım hedefleri dahilindedir.


DÜZENLEME: Alıntıda belirtilen taraf aşağıda kopyalanmıştır.

BİR kenara: SÜREÇİNİZDEN NEDEN HİÇBİR BELLEK YOK

Kısa ömürlü bir program yazarken, tuşlarını kullanarak biraz alan ayırabilirsiniz malloc(). Program çalışıyor ve tamamlanmak üzere: free()çıkmadan hemen önce birkaç kez çağrı yapmanız gerekiyor mu? Olmaması yanlış gibi görünse de, hiçbir bellek gerçek anlamda "kaybolmaz". Nedeni basit: Sistemde gerçekten iki düzey bellek yönetimi var. Bellek yönetiminin ilk seviyesi işletim sistemi tarafından yürütülür ve çalıştığında işlemlere belleği dağıtır ve işlemler çıktığında (veya başka bir şekilde öldüğünde) geri alır. Aradığınızda yönetiminin ikinci düzey yığın içinde örneğin, her sürecin içindedir malloc()ve free(). Aramasanız bilefree()(ve böylece yığıntaki bellek sızıntısı), işletim sistemi, programın çalışması tamamlandığında, işlemin tüm belleğini (kod, yığın ve yığınla ilgili olarak bu sayfalar dahil) geri alacaktır. Adres alanınızdaki yığının durumu ne olursa olsun, işletim sistemi, işlem sona erdiğinde tüm bu sayfaları geri alır, böylece boşaltmamanıza rağmen hiçbir belleğin kaybolmamasını sağlar.

Bu nedenle, kısa ömürlü programlar için, bellek sızıntısı genellikle herhangi bir operasyonel soruna neden olmaz (zayıf form olarak kabul edilebilir). Uzun süredir çalışan bir sunucu (hiçbir zaman çıkmayan bir web sunucusu veya veritabanı yönetim sistemi gibi) yazdığınızda, sızan bellek çok daha büyük bir sorundur ve sonunda uygulama belleği bittiğinde çökmeye neden olur. Ve elbette, bellek sızıntısı belirli bir programın içinde daha da büyük bir sorundur: işletim sisteminin kendisi. Bizi bir kez daha gösteriyoruz: Çekirdek kodunu yazanların hepsinin en zor işi var ...

Sayfa 7 den Bellek API bölüm

İşletim Sistemleri: Üç Kolay Parça
Remzi H. Arpaci-Dusseau ve Andrea C. Arpaci-Dusseau Arpaci-Dusseau Kitapları Mart 2015 (Sürüm 0.90)


4

Değişkenlerinizi serbest bırakmamak için gerçek bir tehlike yoktur , ancak ilk bloğu serbest bırakmadan farklı bir bellek bloğuna bir bellek bloğuna bir işaretçi atarsanız, ilk bloğa artık erişilemez, ancak yine de yer kaplar. Bellek sızıntısı denen şey budur ve bunu düzenli olarak yaparsanız, işleminiz sistem kaynaklarını diğer işlemlerden uzaklaştırarak gittikçe daha fazla bellek tüketmeye başlar.

Süreç kısa ömürlü ise, işlem tamamlandığında tahsis edilen tüm bellek işletim sistemi tarafından geri kazanıldığı için bunu genellikle ortadan kaldırabilirsiniz, ancak daha fazla kullanmadığınız tüm belleği serbest bırakma alışkanlığı edinmenizi tavsiye ederim.


1
İlk ifadeniz için "tehlike yok" için -1 demek istiyorum, ancak o zaman neden tehlike olduğuna dair düşünceli bir cevap vermeniz gerekir.
DevinB

2
Tehlikeler gittikçe iyi huylu - ben her gün bir segfault üzerinde bir bellek sızıntısı alacağım.
Kyle Cronin

1
Çok doğru ve her ikimiz de = D tercih
etmem

2
@KyleCronin Bir bellek sızıntısından çok bir segfault tercih ederim , çünkü her ikisi de ciddi hatalar ve segfaultların tespit edilmesi daha kolaydır. Çoğu zaman bellek sızıntıları "oldukça iyi huylu" oldukları için fark edilmez veya çözülmez. RAM'im ve ben yürekten katılmıyorum.
Dan Bechard

@ Dan Bir geliştirici olarak, kesinlikle. Bir kullanıcı olarak, bellek sızıntısını alacağım. Sızan bellekle de olsa, çalışmayan yazılımın üzerinde çalışan bir yazılım olmasını tercih ederim.
Kyle Cronin

3

Bu konuda kesinlikle haklısınız. Bir değişkenin programın ölümüne kadar var olması gereken küçük önemsiz programlarda, belleğin yeniden konumlandırılmasının gerçek bir yararı yoktur.

Aslında, bir zamanlar programın her bir uygulamasının çok karmaşık ama nispeten kısa ömürlü olduğu bir projeye katıldım ve karar sadece hafızayı tahsis etmeyi ve projeyi yerleştirerek hata yaparak istikrarsızlaştırmamayı amaçladı.

Bununla birlikte, çoğu programda bu gerçekten bir seçenek değildir veya hafızanızın tükenmesine yol açabilir.


2

Doğru, işlem bittiğinde bellek otomatik olarak serbest bırakılır. Bazı insanlar, işlem sona erdiğinde kapsamlı bir temizleme yapmamaya çalışır, çünkü hepsi işletim sistemine bırakılacaktır. Ancak, program çalışırken kullanılmayan belleği boşaltmanız gerekir. Bunu yapmazsanız, çalışma setiniz çok büyürse sonunda tükenebilir veya aşırı sayfalamaya neden olabilirsiniz.


2

Sıfırdan bir uygulama geliştiriyorsanız, ne zaman ücretsiz arayacağınız konusunda bazı eğitimli seçimler yapabilirsiniz. Örnek programınız gayet iyi: hafızayı ayırıyor, belki birkaç saniyeliğine çalışıyorsunuz ve sonra da iddia ettiği tüm kaynakları serbest bırakarak kapanıyor.

Yine de başka bir şey yazıyorsanız - bir sunucu / uzun süredir çalışan bir uygulama veya başka biri tarafından kullanılacak bir kütüphane, mallocasyon yaptığınız her şey için ücretsiz olarak arama yapmayı beklemelisiniz.

Pragmatik tarafı bir saniyeliğine göz ardı ederek, daha katı yaklaşımı takip etmek ve kendinizi mallocasyon yaptığınız her şeyi serbest bırakmak için çok daha güvenlidir. Kod yazarken bellek sızıntılarını izleme alışkanlığınız yoksa, birkaç sızıntıyı kolayca açabilirsiniz. Yani başka bir deyişle, evet - onsuz kaçabilirsiniz; lütfen dikkatli ol.


0

Bir program işletim sisteminden çıkmadan önce birkaç Megabayt boşaltmayı unutursa, işletim sistemi bunları serbest bırakır. Ancak programınız bir seferde haftalarca çalışırsa ve programın içindeki bir döngü, her yinelemede birkaç bayt boşaltmayı unutursa, düzenli olarak yeniden başlatmadığınız sürece bilgisayarınızdaki tüm kullanılabilir belleği tüketecek güçlü bir bellek sızıntısına sahip olursunuz. BASIN => Program, başlangıçta biri için tasarlanmamış olsa bile, ciddi şekilde büyük bir görev için kullanılıyorsa, küçük bellek sızıntıları bile kötü olabilir.


-2

İki örneğinizin aslında sadece bir tane olduğunu düşünüyorum: bu free()sadece sürecin sonunda gerçekleşmelidir, ki belirttiğiniz gibi süreç sona erdiği için işe yaramaz.

Yine de ikinci örnekte, tek fark, malloc()hafızanın tükenmesine yol açabilecek tanımsız bir sayıya izin vermenizdir . Durumu ele almanın tek yolu iade kodunu kontrol etmek malloc()ve buna göre hareket etmektir.

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.