Neden .NET kitaplar yığın vs yığın bellek ayırma hakkında konuşurlar?


36

Her .net kitabı, referans tiplerine karşı değer tiplerinden bahsediyor gibi görünüyor ve her tipin depolandığı (yığın veya yığın) (genellikle yanlış) durumuna işaret ediyor. Genellikle ilk birkaç bölümde yer almaktadır ve bazı önemli hususlar olarak sunulmuştur. Sanırım sertifika sınavlarında bile var . Neden yığın vs yığın bile (acemi) .Net geliştiricileri için önemlidir? Bir şeyler tahsis ediyorsun ve işe yarıyor, değil mi?


11
Bazı yazarlar yeni başlayanlara öğretmek için neyin önemli olduğu ve alakasız gürültü konusunda gerçekten çok kötü yargılara sahiptir. Son zamanlarda gördüğüm bir kitapta, erişim değiştiricilerin ilk adı, 6 yıl boyunca C # hiç kullanmadığım, korunan iç içeriğe zaten
sahipti

1
Tahminime göre, orijinal .Net belgesini kim yazdıysa, o bölüm için bu belgelerin büyük bir kısmını yaptı ve bu belgeler yazarların kitaplarını esasen dayandırdıklarını ve sonra da kaldıklarını söylüyor.
Greg

Değer türlerinin her şeyi kopyaladığını ve referansların olmadığını söyler, bu değerlerin depolandığı yerlerde uygulamaya özel ve hatta alakasız olabileceğinden, referansların neden kullanıldığını anlamak daha anlamlı olur ve daha kolay olur.
Trinidad,

Görüşme kargo kült?
Den

Yanıtlar:


37

Bu bilgi parçasının önemli sayılmasının temel nedeninin gelenek olduğuna ikna oluyorum . Yönetilmeyen ortamlarda, yığınla yığın arasındaki fark önemlidir ve kullandığımız belleği el ile ayırmamız ve silmemiz gerekir. Şimdi, çöp toplama yönetimi önemser, bu yüzden o parçayı görmezden gelirler. Bu mesajın gerçekten elde edildiğini sanmıyorum, ya da ne tür bir hafıza kullanıldığını umursamamız gerekmiyor.

Fede'nin belirttiği gibi, Eric Lippert'in bunun hakkında söyleyecek çok ilginç şeyleri var: http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx .

Bu bilgiler ışığında, ilk paragrafımı temelde okuyacak şekilde ayarlayabilirsiniz: "İnsanların bu bilgiyi içermesi ve bunun önemli olduğunu varsaymasının nedeni, geçmişte bu bilgiye ihtiyaç duymanın yanı sıra yanlış veya eksik bilgilerden kaynaklanmaktadır."

Performans nedenlerinden dolayı hala önemli olduğunu düşünenler için: Bir şeyi ölçmek ve bunun önemli olduğunu bulmak için bir şeyi yığından yığına taşımak için ne gibi eylemler yaparsınız? Daha büyük olasılıkla, sorunlu alan için performansı artırmanın tamamen farklı bir yolunu bulursunuz.


6
Bazı çerçeve uygulamalarında (özellikle Xbox'ta küçük), toplama süresinde (oyunun kendisi) çöp toplama işlemini azaltmak için yapıları kullanmanın daha iyi olduğunu duydum. Yine de başka yerlerde normal tipler kullanıyordunuz, ancak oyun sırasında GC'nin çalışmaması için önceden tahsis edildi. Bu, .NET'te tanıdığım yığın-yığın yığını ile ilgili tek optimizasyonla ilgilidir ve kompakt çerçevenin ve gerçek zamanlı programların ihtiyaçlarına oldukça özeldir.
CodexArcanum

5
Ben çoğunlukla geleneğin argümanına katılıyorum. Bir noktada deneyimli pek çok programcı, doğru ve etkili bir kod istiyorsanız, bunun önem arz ettiği düşük seviyeli bir dilde programlanmış olabilir. Bununla birlikte, örneğin C ++ 'ı yönetilmeyen bir dil olarak alın: Resmi şartname aslında otomatik değişkenlerin yığına gitmesi gerektiğini söylemez . +1
stakx

36

Her .NET kitabı, referans türlerine kıyasla değer türlerinden bahsediyor gibi görünüyor ve her türün depolandığı (yığın veya yığın) (genellikle yanlış) durumuna işaret ediyor. Genellikle ilk birkaç bölümde yer almaktadır ve bazı önemli hususlar olarak sunulmuştur.

Tamamen katılıyorum; Bunu her zaman görüyorum.

.NET kitapları neden yığın bellek yığın bellek ayırma hakkında konuşuyor?

Sebeplerin bir kısmı, birçok insanın C # (veya diğer .NET dillerine) bir C veya C ++ geçmişinden gelmesidir. Bu diller sizin için depolama ömrü hakkındaki kuralları uygulamaz, bu kuralları bilmek ve onları takip etmek için programınızı dikkatle uygulamak zorundasınız.

Şimdi, bu kuralları bilmek ve bunları C içinde takip etmek, "yığın" ve "yığın" ı anlamanızı gerektirmez . Ancak veri yapılarının nasıl çalıştığını anlarsanız, kuralları anlamak ve bunlara uymak genellikle daha kolaydır.

Bir acemi kitabı yazarken bir yazar aynı sırayla kavramları açıklamak için doğaldır onlar bunları öğrendik. Bu mutlaka kullanıcı için anlamlı olan bir düzen değildir. Son zamanlarda Scott Dorman'ın C # 4 başlangıç ​​kitabının teknik editörüydüm ve bu konuda hoşuma giden şeylerden biri, Scott'ın bellek yönetiminde oldukça gelişmiş konuların ne olduğuna başlamaktan ziyade, konular için oldukça mantıklı bir sipariş seçti.

Bunun bir başka nedeni de MSDN dokümantasyonundaki bazı sayfaların depolama ile ilgili hususları kuvvetle vurgulamasıdır. Özellikle ilk günlerde hala asılı olan eski MSDN belgeleri. Bu belgelerin çoğunun, hiçbir zaman eksize edilmeyen ince hataları vardır ve tarihte ve belirli bir kitleye belirli bir zamanda yazıldığını hatırlamanız gerekir.

Neden yığın vs yığın (acemi) .NET geliştiricileri için bile önemlidir?

Bence öyle değil. Anlamak çok daha önemli olan şey şöyle şeylerdir:

  • Referans türü ve değer tipi arasındaki kopya anlambilimindeki fark nedir?
  • "Ref int x" parametresi nasıl davranır?
  • Değer türleri neden değişmez olmalıdır?

Ve bunun gibi.

Bir şeyler tahsis ediyorsun ve işe yarıyor, değil mi?

Bu ideal.

Şimdi, önemli olduğu durumlar var. Çöp toplama işlemi harika ve nispeten ucuz, ancak ücretsiz değil. Küçük yapıların etrafına kopyalanması nispeten ucuzdur, ancak ücretsiz değildir. Toplama baskısının maliyetini aşırı kopyalama maliyetiyle dengelemeniz gereken gerçekçi performans senaryoları vardır. Bu gibi durumlarda, ilgili tüm belleğin boyutu, yeri ve gerçek kullanım ömrü hakkında güçlü bir anlayışa sahip olmak çok yararlıdır.

Benzer şekilde, yığında ne olduğunu ve yığında ne olduğunu ve çöp toplayıcısının etrafında neler hareket edebileceğini bilmek için gerekli olan birlikte çalışma senaryoları da vardır. Bu nedenle C #, "sabit", "stackalloc" gibi özelliklere sahiptir.

Ancak bunların hepsi gelişmiş senaryolardır. İdeal olarak, yeni başlayan bir programcının bunların hiçbiri için endişelenmemesi gerekir.


2
Cevabın için teşekkürler Eric. Konuyla ilgili son blog yayınlarınız, soruyu göndermemi isteyen şeylerden biriydi.
Greg

13

Hepiniz noktayı kaçırıyorsunuz. Yığın / yığın ayrımının önemli olmasının nedeni kapsam nedeniyledir .

struct S { ... }

void f() {
    var x = new S();
    ...
 }

Bir kez x kapsamı dışına gider, oluşturulan nesne kategorik edilir gitti . Bu sadece yığında değil, yığında tahsis edilmesindendir. Bu gerçeği değiştirebilecek olan yöntemin "..." bölümünde yer alan hiçbir şey yok. Özellikle, herhangi bir ödev veya yöntem çağrısı yalnızca S yapısının kopyalarını yapmış olabilir , yaşamı sürdürebilmesi için yeni referanslar oluşturmamış olabilir.

class C { ... }

void f() {
     var x = new C();
     ...
}

Tamamen farklı hikaye! X şimdi yığında olduğundan, nesnesi (yani nesnenin kendisi , bir kopyası değil), x kapsam dışına çıktıktan sonra devam etmeye devam edebilir . Aslında, yaşamaya devam etmeyecek tek yolu , x'in ona tek referans olması. "..." bölümündeki atamalar veya yöntem çağrıları, x kapsam dışı kaldığında hala "canlı" olan başka referanslar oluşturduysa , bu nesne yaşamaya devam edecektir.

Bu çok önemli bir kavramdır ve “neyin ve neden” ini gerçekten anlamanın tek yolu, yığın ve yığın tahsisi arasındaki farkı bilmektir.


Kitaplarda daha önce yığın / yığın tartışmalarıyla birlikte sunulan argümanı gördüğümden emin değilim, ama bu iyi bir şey. +1
Greg

2
Şeklinden dolayı, C # kapakları oluşturur, kod ...neden olabilir xbelirtilen kapsamı dayanmak ve böylece bir derleyici tarafından oluşturulan sınıfının bir alana dönüştürülecek ve. Şahsen, örtük kaldırma fikrini tatsız buluyorum, ancak dil tasarımcıları bunun için geçerli gibi görünüyor (yükseltilmiş herhangi bir değişkenin bunu belirtmek için bir bildirimde bulunmasını zorunlu kılmak yerine). Program doğruluğunu sağlamak için, bir nesnede bulunabilecek tüm referansları hesaba katmak gerekir. Bir rutinin geri döndüğü zaman, gönderilen bir referansın hiçbir kopyasının kalmayacağını bilerek.
supercat,

1
Gelince 'yapılar yığını üzerinde' doğru deyimi bir depolama konumu olarak ilanı halinde olmasıdır structType foo, depolama konumu fooonun alanlarının içeriğini tutan; eğer fooyığın, bu nedenle onun alanlardır. Eğer fooyığın üzerinde yani onun alanlardır. eğer foobir ağa Apple II, yani onun alanlardır. Buna karşılık, eğer foobir sınıf tipi olsaydı null, bir nesneyi ya da bir nesneyi referansı tutardı. Sınıf tipinin foosöylenebileceği tek durum , bir sınıfın tek alanı olsaydı ve kendisine atıfta bulunulursa nesnenin alanlarını tutar.
supercat,

+1, buradaki fikrini seviyorum ve bunun geçerli olduğunu düşünüyorum ... Ancak, kitapların bu konuyu neden bu kadar derinlemesine almasının bir haklı olduğunu düşünmüyorum. Burada anlattıklarınız, kitabın bu 3 veya 4 bölümünü değiştirebilir ve YOL daha yararlı olabilir gibi görünüyor.
Frank V

1
bildiklerime göre, yapılar mecbur değil, ne de onlar gerçekten her zaman yığında gidiyorlar.
sara,

5

NEDEN konuyu ele alıyorlarsa, @Kirk ile anlamanız gereken önemli bir kavram olduğuna katılıyorum. Mekanizmaları ne kadar iyi bilirseniz, düzgün performans gösteren harika uygulamalar yapmak için o kadar iyi bir şey yapabilirsiniz.

Şimdi Eric Lippert , konunun çoğu yazar tarafından doğru şekilde ele alınmadığı konusunda sizinle aynı fikirde görünüyor. Kaputun altında ne olduğunu daha iyi anlamak için blogunu okumanı tavsiye ederim.


2
Eric'in yazısı, bilmeniz gereken tek şeyin değer ve referans türlerinin açık özellikleri olduğu ve uygulamanın aynı kalmasını beklememesi gerektiği anlamına geliyor. Bence, C # 'yı bir yığın olmadan tekrar uygulamak için etkili bir yol olduğunu önermek oldukça yalvarır ama onun amacı doğrudur: bu dil belirtiminin bir parçası değildir. Bu nedenle, bu açıklamayı kullanmamın tek nedeni, diğer dilleri, özellikle de C'yi tanıyan programcılar için faydalı bir alegori olması.
Jeremy

5

Bunun yönetilen ortamların bütün meselesi olduğunu düşündüm. Buna, herhangi bir zamanda değişebileceği için herhangi bir varsayımda bulunmamanız gereken temel çalışma zamanının bir uygulama detayı olarak bile değildim.

.NET hakkında fazla bir şey bilmiyorum, ama bildiğim kadarıyla, yürütmeden önce JITted. Örneğin JIT kaçış analizini yapabilir ve birdenbire ya hiç istemediyseniz, istifler üzerinde ya da sadece bazı kayıtlarda bulunan nesnelere sahip olabilirsiniz. Bunu bilemezsin.

Sanırım bazı kitaplar basitçe yazarlar buna büyük önem atfettiği için ya da izleyicilerinin kabul ettiğini varsaydıkları için (ör. "C ++ programcıları için bir C # yazdıysanız muhtemelen konuyu kapsamalısınız").

Bununla birlikte, “hafıza yönetiliyor” dan daha fazla söylenecek bir şey olmadığını düşünüyorum. Aksi halde insanlar yanlış sonuçlar çıkarabilir.


2

Açıkça yönetmek zorunda olmasanız bile, bellek ayırmanın onu verimli bir şekilde kullanmak için nasıl çalıştığını anlamanız gerekir. Bu, bilgisayar bilimindeki hemen hemen her soyutlama için geçerlidir.


2
Yönetilen dillerde, bir değer tipi ile referans tipi arasındaki farkı bilmek zorundasınız, ancak bunun ötesinde, kaputun altında nasıl yönetildiğini düşünerek aksın etrafına sarılmak kolaydır. Örnek için buraya bakın: stackoverflow.com/questions/4083981/…
Robert Harvey

Robert ile aynı fikirdeyim

Tahsis edilen yığın ile tahsis edilen yığın arasındaki fark, değer ve referans tipleri arasındaki farkı tam olarak açıklayan şeydir.
Jeremy


1
Jeremy yığın ve ayırma arasındaki fark edemez zaman süreleri vardır, çünkü değer türleri ve referans türleri arasındaki farklı davranış açıklar iki değer türleri ve referans türleri yığın üzerinde olan ve yine de farklı davranır. Anlaşılması gereken en önemli şey (örneğin) referans türleri ve değer türleri için referans-by-pass kullanmanız gerektiğindedir. Bu sadece "öbek üzerinde" değil, bir değer türü veya başvuru türü "olduğuna bağlıdır.
Tim Goodman,

2

Fark yaratabilecek bazı uç durumlar olabilir. Yığın birkaç konser olurken, varsayılan yığın alanı 1meg'dir. Bu nedenle, çözümünüz çok sayıda nesneyi tutarsa, yığın alanı yeterliyken yığın alanınız tükenebilir.

Ancak, çoğunlukla, oldukça akademik.


Evet, ancak bu kitapların hiçbirinin referansların yığında saklandığını açıklamak için acı çektiğinden şüpheliyim - bu nedenle, bir yığın taşma olabileceğine dair çok sayıda referans türünüz veya çok sayıda değer türünün olması önemli değil.
Jeremy

0

Söylediğiniz gibi, C # 'nın bellek yönetimini ortadan kaldırması gerekiyordu ve yığın-yığın yığınına karşı yığın teorik olarak geliştiricinin bilmesi gerekmeyen uygulama detayları.

Sorun, bazı şeylerin bu uygulama detaylarına atıfta bulunmadan sezgisel bir şekilde açıklamak gerçekten zor olmasıdır. Değişken değer türlerini değiştirirken gözlemlenebilir davranışı açıklamaya çalışın - yığın / yığın ayrımına atıfta bulunmadan yapmanız neredeyse imkansızdır. Veya neden dilde değer türlerinin en başta olduğunu ve ne zaman kullanacağınızı açıklamaya çalışın mı? Dilin anlaşılması için ayrımı anlamanız gerekir.

Unutmayın ki Python ya da JavaScript dediğimiz kitaplar, ondan bahsetseler bile, bundan büyük bir şey yapmazlar. Bunun nedeni, her şeyin tahsis edilmiş ya da değiştirilemeyen yığın olmalarıdır, yani farklı kopyalama semantikleri hiçbir zaman devreye girmez. Bu dillerde hafızanın soyutlanması işe yarıyor, C # dilinde sızdırıyor.

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.