C de malloc()
öbekteki bir bellek bölgesini tahsis eder ve ona bir işaretçi döndürür. Tüm elde ettiğiniz bu. Bellek başlatılmaz ve bunların tamamen sıfır veya başka bir şey olduğunu garanti etmezsiniz.
Java'da arama new
, yığın tabanlı bir ayırma gibi yapar malloc()
, ancak ayrıca bir ton ek kolaylık elde edersiniz (veya isterseniz ek yük). Örneğin, ayrılacak bayt sayısını açıkça belirtmeniz gerekmez. Derleyici, ayırmaya çalıştığınız nesnenin türüne göre bunu sizin için bulur. Ayrıca, nesne yapıcıları çağrılır (başlatmanın nasıl gerçekleştiğini denetlemek isteyip istemediğinizi bağımsız değişkenlere iletebilirsiniz). Geri new
döndüğünde, başlatılmış bir nesneye sahip olmanız garanti edilir.
Ama evet, çağrı hem sonucu sonunda malloc()
ve new
sadece yığın tabanlı verilerin bazı yığın göstericisidir.
Sorunuzun ikinci kısmı, bir yığın ile yığın arasındaki farkları sorar. Derleyici tasarımı hakkında bir ders alarak (veya hakkında bir kitap okuyarak) çok daha kapsamlı cevaplar bulunabilir. İşletim sistemleri üzerine bir kurs da yardımcı olacaktır. Ayrıca yığınlar ve yığınlar hakkında SO üzerinde çok sayıda soru ve cevap vardır.
Bunu söyledikten sonra, umarım çok ayrıntılı değildir ve farklılıkları oldukça yüksek bir düzeyde açıklamayı amaçlamaktadır.
Temel olarak, iki bellek yönetim sistemine sahip olmanın temel nedeni, yani bir yığın ve yığın, verimlilik içindir . İkincil bir sebep, her birinin belirli tür problemlerde diğerinden daha iyi olmasıdır.
Yığınlar kavram olarak anlamam biraz daha kolay, bu yüzden yığınlarla başlıyorum. Bu işlevi C dilinde ele alalım ...
int add(int lhs, int rhs) {
int result = lhs + rhs;
return result;
}
Yukarıdakiler oldukça basit görünüyor. add()
Sol ve sağ ekler adında bir işlev tanımlar ve iletiriz. İşlev bunları ekler ve bir sonuç döndürür. Lütfen oluşabilecek taşmalar gibi tüm uç durumları göz ardı edin, bu noktada tartışma konusu değildir.
add()
İşlevin amacı oldukça basit görünüyor, ama biz onun ömrü ile ilgili ne söylersin? Özellikle bellek kullanımı ihtiyacı var mı?
En önemlisi, derleyici , veri türlerinin ne kadar büyük olduğunu ve kaç tanesinin kullanılacağını önceden bilir (yani derleme zamanında). lhs
Ve rhs
bağımsız değişkenler olarak sizeof(int)
4 adet bayt. Değişken result
de sizeof(int)
. Derleyici, add()
işlevin 4 bytes * 3 ints
veya toplam 12 bayt bellek kullandığını söyleyebilir .
Zaman add()
fonksiyonu olarak adlandırılır, bir donanım yazmacı adı yığın işaretçisi yığının üstüne noktalarının içinde bir adres vardır. add()
İşlevin çalışması için gereken belleği ayırmak için , tüm işlev giriş kodu, yığın işaretçisi kayıt değerini 12 oranında azaltmak için tek bir montaj dili talimatı verir. Bunu yaparken, yığın üzerinde üç kişilik depolama alanı oluşturur. ints
her biri bir için lhs
, rhs
ve result
. Tek bir komut uygulayarak ihtiyacınız olan bellek alanını elde etmek, hız açısından büyük bir kazançtır çünkü tek komutlar bir saat işareti (1 GHz CPU saniyede 1 milyarda biri) yürütme eğilimindedir.
Ayrıca, derleyicinin görünümünden, bir dizini dizine eklemek gibi çok fazla görünen değişkenlere bir harita oluşturabilir:
lhs: ((int *)stack_pointer_register)[0]
rhs: ((int *)stack_pointer_register)[1]
result: ((int *)stack_pointer_register)[2]
Yine, tüm bunlar çok hızlı.
Ne zaman add()
fonksiyonu çıkar o temizlemek zorundadır. Bunu, yığın işaretçisi kaydından 12 bayt çıkararak yapar. Bir çağrıya benzer, free()
ancak yalnızca bir CPU talimatı kullanır ve sadece bir onay alır. Çok, çok hızlı.
Şimdi yığın tabanlı bir ayırmayı düşünün. Ne kadar belleğe ihtiyacımız olacağını önceden bilmediğimizde bu devreye girer (yani yalnızca çalışma zamanında öğreneceğiz).
Bu işlevi göz önünde bulundurun:
int addRandom(int count) {
int numberOfBytesToAllocate = sizeof(int) * count;
int *array = malloc(numberOfBytesToAllocate);
int result = 0;
if array != NULL {
for (i = 0; i < count; ++i) {
array[i] = (int) random();
result += array[i];
}
free(array);
}
return result;
}
addRandom()
Fonksiyonun derleme sırasında count
argümanın değerinin ne olacağını bilmediğine dikkat edin . Bu nedenle array
, yığını yığına koyarsak, bizim gibi tanımlamaya çalışmak mantıklı değil :
int array[count];
Eğer count
büyük bizim yığını çok büyük ve üzerine yazma diğer program segmentlerini büyümeye neden olabilir. Bu yığın taşması gerçekleştiğinde programınız çöker (veya daha kötüsü).
Bu nedenle, çalışma zamanına kadar ne kadar belleğe ihtiyacımız olacağını bilmediğimiz durumlarda kullanırız malloc()
. Daha sonra ihtiyacımız olduğunda ihtiyacımız olan bayt sayısını isteyebiliriz ve malloc()
o kadar bayt satabildiğini kontrol edeceğiz. Mümkünse, harika, geri alıyoruz, eğer değilse, bize malloc()
başarısız olma çağrısını söyleyen bir NULL işaretçisi alırız . Özellikle, program çökmez! Elbette programcı olarak, kaynak tahsisi başarısız olursa programınızın çalışmasına izin verilmeyeceğine siz karar verebilirsiniz, ancak programcı tarafından başlatılan sonlandırma sahte bir çökmeden farklıdır.
Şimdi verimliliğe bakmak için geri dönmeliyiz. Yığın ayırıcı süper hızlıdır - tahsis edilecek bir talimat, dağıtmak için bir talimat ve derleyici tarafından yapılır, ancak yığının bilinen büyüklükteki yerel değişkenler gibi şeyler için tasarlandığını unutmayın, bu nedenle oldukça küçük olma eğilimindedir.
Öte yandan, öbek ayırıcısı birkaç kat daha yavaştır. Kullanıcının istediği bellek miktarını satabilmek için yeterli boş belleğe sahip olup olmadığını görmek için tablolarda bir arama yapmalıdır. Kimsenin bu bloğu kullanamayacağından emin olmak için belleği çıkardıktan sonra bu tabloları güncellemesi gerekir (bu defter tutma, ayırıcıdan satmayı planladığı şeyin yanı sıra kendisinin de bellek ayırmasını gerektirebilir ). Ayırıcı, belleği güvenli bir şekilde geçirdiğinden emin olmak için kilitleme stratejileri kullanmalıdır. Ve hafıza sonundafree()
Farklı zamanlarda gerçekleşen ve öngörülebilir bir sırada olmayan, d: ayırıcı, bitişik bloklar bulmak ve yığın parçalanmasını onarmak için bunları birleştirmek zorundadır. Bunların hepsini gerçekleştirmek için tek bir CPU komutundan daha fazlasını alacak gibi görünüyorsa, haklısınız! Çok karmaşık ve biraz zaman alıyor.
Ancak yığınlar büyük. Yığınlardan çok daha büyük. Onlardan çok fazla bellek alabiliriz ve derleme zamanında ne kadar belleğe ihtiyacımız olacağını bilmediğimizde harika olurlar. Bu yüzden, çok büyük bir şey ayırmaya çalıştığımızda çökmek yerine bizi kibarca reddeden yönetilen bir bellek sistemi için hızdan ödün veriyoruz.
Umarım bu bazı sorularınızı yanıtlamanıza yardımcı olur. Yukarıdakilerden herhangi biri hakkında açıklama yapmak istiyorsanız lütfen bize bildirin.