Mengapa .Net buku berbicara tentang alokasi memori tumpukan vs tumpukan?


36

Sepertinya setiap buku .net berbicara tentang tipe nilai vs tipe referensi dan menjadikannya sebagai titik (sering salah) menyatakan di mana setiap tipe disimpan - heap atau stack. Biasanya ada di beberapa bab pertama dan disajikan sebagai fakta yang sangat penting. Saya pikir itu bahkan tercakup dalam ujian sertifikasi . Mengapa stack vs heap bahkan penting bagi (pemula). Pengembang net? Anda mengalokasikan barang dan hanya berfungsi, bukan?


11
Beberapa penulis hanya memiliki penilaian yang sangat buruk tentang apa yang penting untuk diajarkan kepada pemula dan apa kebisingan yang tidak relevan. Dalam sebuah buku yang saya lihat baru-baru ini, penyebut pertama pengubah akses sudah termasuk yang dilindungi internal , yang saya tidak pernah gunakan dalam 6 tahun C # ...
Timwi

1
Dugaan saya adalah bahwa siapa pun yang menulis dokumentasi .Net yang asli untuk bagian itu membuat masalah besar, dan dokumentasi itulah yang menjadi dasar penulisnya pada buku-buku mereka, dan kemudian tinggal diam saja.
Greg

Mengatakan bahwa tipe nilai menyalin seluruh hal di sekitar dan referensi tidak, akan lebih masuk akal dan lebih mudah untuk memahami mengapa menggunakan referensi, karena di mana nilai-nilai tersebut disimpan dapat menjadi implementasi spesifik, dan bahkan tidak relevan.
Trinidad

Wawancara kultus kargo?
Den

Jawaban:


37

Saya menjadi yakin bahwa alasan utama informasi ini dianggap penting adalah tradisi. Dalam lingkungan yang tidak dikelola, perbedaan antara tumpukan dan tumpukan adalah penting dan kami harus mengalokasikan dan menghapus memori yang kami gunakan secara manual. Sekarang, pengumpulan sampah mengurus manajemen, sehingga mereka mengabaikan bagian itu. Saya tidak berpikir pesannya benar-benar telah melalui bahwa kita tidak perlu peduli jenis memori yang digunakan juga.

Seperti yang ditunjukkan oleh Fede, Eric Lippert memiliki beberapa hal yang sangat menarik untuk dikatakan tentang ini: http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx .

Mengingat informasi itu, Anda dapat menyesuaikan paragraf pertama saya dengan membaca: "Alasan orang memasukkan informasi ini dan menganggapnya penting adalah karena informasi yang salah atau tidak lengkap dikombinasikan dengan kebutuhan pengetahuan ini di masa lalu."

Bagi mereka yang berpikir itu masih penting untuk alasan kinerja: Tindakan apa yang akan Anda ambil untuk memindahkan sesuatu dari tumpukan ke tumpukan jika Anda mengukur sesuatu dan mengetahui bahwa itu penting? Kemungkinan besar, Anda akan menemukan cara yang sama sekali berbeda untuk meningkatkan kinerja untuk area masalah.


6
Saya telah mendengar bahwa dalam beberapa implementasi kerangka kerja (kompak pada Xbox khusus) lebih baik menggunakan struct selama periode rendering (permainan itu sendiri) untuk mengurangi pengumpulan sampah. Anda masih akan menggunakan tipe normal di tempat lain, tetapi telah dialokasikan sebelumnya sehingga GC tidak akan berjalan selama pertandingan. Itu tentang satu-satunya optimisasi mengenai tumpukan vs tumpukan yang saya ketahui di .NET, dan ini cukup spesifik untuk kebutuhan kerangka kerja ringkas dan program waktu nyata.
CodexArcanum

5
Saya sebagian besar setuju dengan argumen tradisi. Banyak programmer berpengalaman di beberapa titik mungkin telah diprogram dalam bahasa tingkat rendah di mana hal ini penting jika Anda menginginkan kode yang benar dan efisien. Namun, ambil C ++ sebagai contoh, bahasa yang tidak dikelola: Spesifikasi resmi tidak benar-benar mengatakan bahwa variabel otomatis harus ada di stack, dll. Standar C ++ memperlakukan stack dan heap sebagai detail implementasi. +1
stakx

36

Sepertinya setiap buku .NET berbicara tentang tipe nilai vs tipe referensi dan menjadikannya sebagai titik (sering salah) menyatakan di mana setiap tipe disimpan - heap atau stack. Biasanya ada di beberapa bab pertama dan disajikan sebagai fakta yang sangat penting.

Aku sangat setuju; Saya melihat ini setiap waktu.

Mengapa .NET buku berbicara tentang alokasi memori tumpukan vs tumpukan?

Salah satu bagian dari alasannya adalah karena banyak orang datang ke C # (atau bahasa .NET lainnya) dari latar belakang C atau C ++. Karena bahasa-bahasa itu tidak memberlakukan bagi Anda peraturan tentang masa penyimpanan, Anda diharuskan untuk mengetahui aturan-aturan itu dan mengimplementasikan program Anda dengan cermat untuk mengikutinya.

Sekarang, mengetahui aturan itu dan mengikutinya dalam C tidak mengharuskan Anda memahami "heap" dan "the stack". Tetapi jika Anda benar-benar mengerti bagaimana struktur data bekerja maka seringkali lebih mudah untuk memahami dan mengikuti aturan.

Ketika menulis buku pemula, wajar bagi penulis untuk menjelaskan konsep-konsep dalam urutan yang sama itu mereka pelajari. Itu belum tentu urutan yang masuk akal bagi pengguna. Saya baru-baru ini menjadi editor teknis untuk buku pemula C # 4 Scott Dorman, dan salah satu hal yang saya sukai adalah Scott memilih pemesanan yang cukup masuk akal untuk topik-topik tersebut, daripada memulai dengan topik yang sebenarnya cukup canggih dalam manajemen memori.

Bagian lain dari alasannya adalah bahwa beberapa halaman dalam dokumentasi MSDN sangat menekankan pertimbangan penyimpanan. Dokumentasi MSDN yang lebih tua yang masih berkeliaran sejak awal. Sebagian besar dokumentasi memiliki kesalahan kecil yang tidak pernah dihapuskan, dan Anda harus ingat bahwa itu ditulis pada waktu tertentu dalam sejarah dan untuk audiens tertentu.

Mengapa stack vs heap bahkan penting bagi (pemula) .NET developer?

Menurut saya, tidak. Yang jauh lebih penting untuk dipahami adalah hal-hal seperti:

  • Apa perbedaan dalam semantik salinan antara tipe referensi dan tipe nilai?
  • Bagaimana parameter "ref int x" berperilaku?
  • Mengapa tipe nilai harus berubah?

Dan seterusnya.

Anda mengalokasikan barang dan hanya berfungsi, bukan?

Itu yang ideal.

Sekarang, ada situasi di mana itu penting. Pengumpulan sampah luar biasa dan relatif murah, tetapi tidak gratis. Menyalin struktur kecil di sekitar relatif murah, tetapi tidak gratis. Ada skenario kinerja realistis di mana Anda harus menyeimbangkan biaya tekanan pengumpulan dengan biaya menyalin berlebihan. Dalam kasus tersebut, sangat membantu untuk memiliki pemahaman yang kuat tentang ukuran, lokasi, dan masa pakai aktual semua memori yang relevan.

Demikian pula, ada skenario interop realistis di mana perlu untuk mengetahui apa yang ada di tumpukan dan apa yang ada di tumpukan, dan apa yang bisa dipindahkan oleh pengumpul sampah. Itu sebabnya C # memiliki fitur-fitur seperti "fix", "stackalloc" dan sebagainya.

Tapi itu semua adalah skenario tingkat lanjut. Idealnya seorang programmer pemula perlu khawatir tentang hal-hal ini.


2
Terima kasih atas jawabannya Eric. Posting blog terbaru Anda tentang hal ini adalah apa yang sebenarnya mendorong saya untuk mengirim pertanyaan.
Greg

13

Kalian semua kehilangan intinya. Alasan mengapa perbedaan tumpukan / tumpukan penting karena ruang lingkup .

struct S { ... }

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

Setelah x keluar dari ruang lingkup, objek yang dibuat akan hilang . Itu hanya karena dialokasikan pada tumpukan, bukan tumpukan. Tidak ada yang bisa masuk dalam bagian "..." dari metode yang dapat mengubah fakta itu. Secara khusus, setiap penugasan atau panggilan metode hanya bisa membuat salinan S struct, tidak membuat referensi baru untuk memungkinkannya tetap hidup.

class C { ... }

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

Cerita yang sangat berbeda! Karena x sekarang ada di heap , objeknya (yaitu, objek itu sendiri , bukan salinannya) bisa sangat baik untuk terus hidup setelah x keluar dari ruang lingkup. Faktanya, satu-satunya cara ia tidak akan terus hidup adalah jika x adalah satu-satunya referensi untuk itu. Jika tugas atau metode panggilan di bagian "..." telah membuat referensi lain yang masih "hidup" pada saat x keluar dari ruang lingkup, maka objek itu akan terus hidup.

Itu adalah konsep yang sangat penting, dan satu-satunya cara untuk benar-benar memahami "apa dan mengapa" adalah mengetahui perbedaan antara tumpukan dan alokasi tumpukan.


Saya tidak yakin saya pernah melihat argumen yang disajikan sebelumnya dalam buku bersama dengan diskusi tumpukan / tumpukan, tapi itu bagus. +1
Greg

2
Karena cara C # menghasilkan penutupan, kode dalam ...dapat menyebabkan xdikonversi ke bidang kelas yang dihasilkan kompiler, dan dengan demikian bertahan lebih lama dari ruang lingkup yang ditunjukkan. Secara pribadi, saya merasa tidak senang dengan gagasan untuk mengangkat secara implisit, tetapi perancang bahasa tampaknya mendukungnya (sebagai kebalikan dari keharusan bahwa setiap variabel yang diangkat memiliki sesuatu dalam deklarasi untuk menentukannya). Untuk memastikan kebenaran program, seringkali perlu memperhitungkan semua referensi yang mungkin ada pada suatu objek. Mengetahui bahwa pada saat suatu rutin kembali, tidak ada salinan referensi yang berlalu akan tetap berguna.
supercat

1
Adapun 'struct berada di stack', pernyataan yang tepat adalah bahwa jika lokasi penyimpanan dinyatakan structType foo, lokasi penyimpanan foomenyimpan konten bidangnya; jika fooada di tumpukan, begitu juga bidangnya. Jika fooada di heap, begitu juga bidangnya. jika fooada dalam jaringan Apple II, begitu pula bidangnya. Sebaliknya, jika fooadalah tipe kelas, itu akan menampung null, atau referensi ke objek. Satu-satunya situasi di mana tipe kelas foodapat dikatakan menahan bidang objek adalah jika itu adalah satu-satunya bidang kelas, dan memegang referensi untuk dirinya sendiri.
supercat

+1, saya suka wawasan Anda di sini dan saya pikir itu valid ... Namun, saya tidak merasa itu alasan mengapa buku-buku membahas topik ini secara mendalam. Sepertinya apa yang Anda jelaskan di sini dapat menggantikan 3 atau 4 bab dari buku tersebut dan menjadi WAY lebih bermanfaat.
Frank V

1
dari yang saya tahu, struct tidak harus, juga tidak selalu pergi di stack.
Sara

5

Mengenai MENGAPA mereka membahas topik, saya setuju dengan @Kirk bahwa ini adalah konsep penting, yang harus Anda pahami. Semakin baik Anda mengetahui mekanismenya, semakin baik yang dapat Anda lakukan untuk membuat aplikasi hebat yang berkinerja lancar.

Sekarang Eric Lippert tampaknya setuju dengan Anda bahwa topik tersebut tidak dibahas dengan benar oleh sebagian besar penulis. Saya sarankan Anda membaca blog-nya untuk mencapai pemahaman yang bagus tentang apa yang ada di balik tudung.


2
Yah posting Eric membuat titik bahwa semua yang perlu Anda ketahui adalah karakteristik terbuka dari nilai dan jenis referensi, dan seharusnya tidak mengharapkan implementasi bahkan tetap sama. Saya pikir itu cukup pertanyaan memohon untuk menyarankan ada cara yang efisien untuk menerapkan kembali C # tanpa tumpukan tetapi maksudnya benar: itu bukan bagian dari spesifikasi bahasa. Jadi satu-satunya alasan untuk menggunakan penjelasan ini yang dapat saya pikirkan adalah bahwa ini merupakan alegori yang berguna bagi programmer yang tahu bahasa lain, terutama C. Selama mereka tahu itu alegori, yang banyak literatur tidak menjelaskannya.
Jeremy

5

Yah, saya pikir itulah inti dari lingkungan yang dikelola. Saya bahkan akan menyebut ini sebagai detail implementasi runtime yang mendasari bahwa Anda TIDAK boleh membuat asumsi, karena itu bisa berubah kapan saja.

Aku tidak tahu banyak tentang. JIT misalnya dapat melakukan analisis pelarian dan apa yang tidak dan tiba-tiba Anda akan memiliki benda-benda yang tergeletak di tumpukan atau hanya di beberapa register. Anda tidak dapat mengetahui hal ini.

Saya kira beberapa buku menutupinya hanya karena penulis menganggapnya sangat penting, atau karena mereka menganggap audiens mereka (misalnya jika Anda menulis "C # untuk programmer C ++" Anda mungkin harus membahas topik tersebut).

Meskipun demikian, saya pikir tidak banyak yang bisa dikatakan selain "memori dikelola". Kalau tidak, orang mungkin menarik kesimpulan yang salah.


2

Anda harus memahami bagaimana alokasi memori berfungsi untuk menggunakannya secara efisien bahkan jika Anda tidak harus mengelolanya secara eksplisit. Ini berlaku untuk hampir setiap abstraksi dalam ilmu komputer.


2
Dalam bahasa yang dikelola, Anda harus mengetahui perbedaan antara tipe nilai dan tipe referensi, tetapi lebih dari itu, mudah untuk melilit poros memikirkan bagaimana dikelola di bawah kap. Lihat di sini untuk contoh: stackoverflow.com/questions/4083981/…
Robert Harvey

Saya harus setuju dengan Robert

Perbedaan antara heap yang dialokasikan dan stack yang dialokasikan adalah apa yang menjelaskan perbedaan antara nilai dan tipe referensi.
Jeremy


1
Jeremy, perbedaan antara heap dan alokasi stack tidak dapat menjelaskan perilaku yang berbeda antara tipe nilai dan tipe referensi, karena ada kalanya kedua tipe nilai dan tipe referensi ada di heap, namun mereka berperilaku berbeda. Hal yang lebih penting untuk dipahami adalah (misalnya) ketika Anda harus menggunakan pass-by-reference untuk tipe referensi vs tipe nilai. Ini hanya tergantung pada "apakah itu tipe nilai atau tipe referensi", bukan "apakah ada di heap".
Tim Goodman

2

Mungkin ada beberapa kasus tepi di mana hal itu dapat membuat perbedaan. Ruang stack default adalah 1meg sementara heapnya beberapa manggung. Jadi, jika Anda memegang sejumlah besar objek, Anda dapat kehabisan ruang stack sambil memiliki banyak ruang tumpukan.

Namun, sebagian besar cukup akademis.


Ya tapi saya ragu salah satu dari buku-buku ini bersusah payah untuk menjelaskan bahwa referensi itu sendiri disimpan di stack - jadi tidak masalah jika Anda memiliki banyak tipe referensi atau banyak tipe nilai Anda masih dapat memiliki stack overflow.
Jeremy

0

Seperti yang Anda katakan, C # seharusnya mengabstraksi manajemen memori, dan heap versus stack stack adalah detail implementasi yang menurut teori pengembang tidak perlu diketahui.

Masalahnya adalah beberapa hal sangat sulit dijelaskan dengan cara yang intuitif tanpa merujuk pada detail implementasi ini. Cobalah untuk menjelaskan perilaku yang dapat diobservasi ketika Anda memodifikasi tipe nilai yang bisa berubah - hampir tidak mungkin dilakukan tanpa merujuk pada perbedaan tumpukan / tumpukan. Atau coba jelaskan mengapa bahkan memiliki tipe nilai dalam bahasa di tempat pertama, dan kapan Anda akan menggunakannya? Anda perlu memahami perbedaan untuk memahami bahasa.

Perhatikan bahwa buku-buku tentang katakanlah Python atau JavaScript tidak membuat masalah besar jika mereka menyebutkannya. Ini karena semuanya baik tumpukan dialokasikan atau tidak berubah, yang berarti semantik menyalin tidak pernah ikut bermain. Dalam bahasa-bahasa itu, abstraksi memori berfungsi, dalam C # itu bocor.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.