Sepertinya saya bahwa segala sesuatu yang dapat dilakukan dengan tumpukan dapat dilakukan dengan tumpukan, tetapi tidak semua yang bisa dilakukan dengan tumpukan dapat dilakukan dengan tumpukan. Apakah itu benar? Maka demi kesederhanaan, dan bahkan jika kita kehilangan sedikit kinerja dengan beban kerja tertentu, tidak bisakah lebih baik hanya dengan satu standar (yaitu, tumpukan)?
Pikirkan pertukaran antara modularitas dan kinerja. Saya tahu itu bukan cara terbaik untuk menggambarkan skenario ini, tetapi secara umum tampaknya kesederhanaan pemahaman dan desain bisa menjadi pilihan yang lebih baik bahkan jika ada potensi kinerja yang lebih baik.
Jawaban:
Tumpukan buruk pada alokasi memori cepat dan deallokasi. Jika Anda ingin mengambil banyak memori dalam durasi terbatas, tumpukan bukanlah pilihan terbaik Anda. Tumpukan, dengan algoritma alokasi / dealokasi super-sederhana, secara alami unggul dalam hal ini (bahkan lebih lagi jika itu dimasukkan ke dalam perangkat keras), itulah sebabnya orang menggunakannya untuk hal-hal seperti meneruskan argumen ke fungsi dan menyimpan variabel lokal - yang paling Kelemahan penting adalah bahwa ia memiliki ruang terbatas, dan dengan demikian menyimpan benda-benda besar di dalamnya, atau mencoba menggunakannya untuk benda berumur panjang, keduanya adalah ide yang buruk.
Menyingkirkan tumpukan sepenuhnya demi menyederhanakan bahasa pemrograman adalah cara IMO yang salah - pendekatan yang lebih baik adalah mengabstraksi perbedaan, biarkan kompiler mencari tahu jenis penyimpanan yang akan digunakan, sementara programmer mengumpulkan lebih tinggi- konstruksi tingkat yang lebih dekat dengan cara manusia berpikir - dan pada kenyataannya, bahasa tingkat tinggi seperti C #, Java, Python dll melakukan hal ini. Mereka menawarkan sintaks yang hampir identik untuk objek yang dialokasikan heap dan primitif yang dialokasikan stack ('tipe referensi' vs 'tipe nilai' dalam .NET lingo), baik sepenuhnya transparan, atau dengan beberapa perbedaan fungsional yang harus Anda pahami untuk menggunakan bahasa dengan benar (tetapi Anda tidak benar-benar harus tahu bagaimana tumpukan dan tumpukan bekerja secara internal).
sumber
Sederhananya, tumpukan bukanlah sedikit kinerja. Ini ratusan atau ribuan kali lebih cepat dari heap. Selain itu, sebagian besar mesin modern memiliki dukungan perangkat keras untuk stack (seperti x86) dan fungsionalitas perangkat keras untuk misalnya tumpukan panggilan tidak dapat dihapus.
sumber
Tidak
Area tumpukan dalam C ++ sangat cepat dibandingkan. Saya berani tidak pengembang C ++ berpengalaman akan terbuka untuk menonaktifkan fungsi itu.
Dengan C ++, Anda memiliki pilihan dan Anda memiliki kendali. Para desainer tidak terlalu tertarik untuk memperkenalkan fitur-fitur yang menambah waktu atau ruang eksekusi yang signifikan.
Melatih pilihan itu
Jika Anda ingin membangun perpustakaan atau program yang mengharuskan setiap objek dialokasikan secara dinamis, Anda bisa melakukannya dengan C ++. Ini akan berjalan relatif lambat, tetapi Anda kemudian dapat memiliki 'modularitas' itu. Bagi kita semua, modularitas selalu opsional, memperkenalkannya sesuai kebutuhan karena keduanya diperlukan untuk implementasi yang baik / cepat.
Alternatif
Ada bahasa lain yang mengharuskan penyimpanan untuk setiap objek dibuat di heap; itu sangat lambat, sehingga kompromi desain (program dunia nyata) dengan cara yang lebih buruk daripada harus belajar keduanya (IMO).
Keduanya penting, dan C ++ memberi Anda kekuatan menggunakan keduanya secara efektif untuk setiap skenario yang diberikan. Karena itu, bahasa C ++ mungkin tidak ideal untuk desain Anda, jika faktor-faktor ini dalam OP Anda penting bagi Anda (misalnya, baca tentang bahasa tingkat yang lebih tinggi).
sumber
Sebenarnya hit kinerja kemungkinan besar!
Seperti yang orang lain tunjukkan tumpukan adalah struktur yang sangat efisien untuk mengelola data yang mematuhi aturan LIFO (terakhir masuk pertama keluar). Alokasi / pembebasan memori pada stack biasanya hanya perubahan pada register pada CPU. Mengubah register hampir selalu merupakan salah satu operasi tercepat yang dapat dilakukan prosesor.
Tumpukan biasanya struktur data yang cukup kompleks dan mengalokasikan / membebaskan memori akan membutuhkan banyak instruksi untuk melakukan semua pembukuan terkait. Lebih buruk lagi, dalam implementasi umum, setiap panggilan untuk bekerja dengan heap memiliki potensi untuk menghasilkan panggilan ke sistem operasi. Panggilan sistem operasi sangat memakan waktu! Program biasanya harus beralih dari mode pengguna ke mode kernel, dan setiap kali ini terjadi, sistem operasi dapat memutuskan bahwa program lain memiliki kebutuhan yang lebih mendesak, dan bahwa program Anda harus menunggu.
sumber
Simula menggunakan heap untuk semuanya. Menempatkan segala sesuatu di tumpukan selalu menginduksi satu tingkat lebih banyak tipuan untuk variabel lokal, dan itu memberi tekanan tambahan pada Pengumpul Sampah (Anda harus memperhitungkan bahwa Pengumpul Sampah benar-benar tersedot saat itu). Itulah sebagian alasan mengapa Bjarne menemukan C ++.
sumber
Tumpukan sangat efisien untuk data LIFO, seperti meta-data yang terkait dengan panggilan fungsi, misalnya. Tumpukan juga memanfaatkan fitur desain yang melekat pada CPU. Karena kinerja pada level ini sangat mendasar bagi hampir semua hal lain dalam suatu proses, mengambil hit "kecil" pada level itu akan menyebar sangat luas. Selain itu, tumpukan memori dapat dipindahkan oleh OS, yang akan mematikan tumpukan. Sementara stack dapat diimplementasikan dalam heap, itu membutuhkan overhead yang akan memengaruhi setiap bagian dari proses pada level paling granular.
sumber
"efisien" dalam hal Anda menulis kode mungkin, tetapi tentu saja tidak dalam hal efisiensi perangkat lunak Anda. Alokasi tumpukan pada dasarnya gratis (hanya dibutuhkan beberapa instruksi mesin untuk memindahkan stack pointer dan menyimpan ruang pada stack untuk variabel lokal).
Karena alokasi tumpukan hampir tidak memerlukan waktu, alokasi bahkan pada tumpukan yang sangat efisien akan 100k (jika tidak 1M +) kali lebih lambat.
Sekarang bayangkan berapa banyak variabel lokal dan struktur data lain yang digunakan aplikasi tipikal. Setiap "i" kecil yang Anda gunakan sebagai penghitung putaran dialokasikan sejuta kali lebih lambat.
Tentu jika perangkat kerasnya cukup cepat, Anda bisa menulis aplikasi yang hanya menggunakan heap. Tetapi sekarang gambarkan aplikasi seperti apa yang bisa Anda tulis jika Anda memanfaatkan heap dan menggunakan perangkat keras yang sama.
sumber
Anda mungkin tertarik pada "Pengumpulan Sampah Cepat, tetapi Tumpukan Lebih Cepat".
http://dspace.mit.edu/bitstream/handle/1721.1/6622/AIM-1462.ps.Z
Jika saya membacanya dengan benar, orang-orang ini memodifikasi kompiler C untuk mengalokasikan "stack frames" di heap, dan kemudian menggunakan pengumpulan sampah untuk tidak mengalokasikan frame alih-alih membuka stack.
"Stack frames" yang dialokasikan tumpukan mengungguli "stack frames" yang dialokasikan dengan tegas.
sumber
Bagaimana tumpukan panggilan akan berfungsi pada tumpukan? Pada dasarnya, Anda harus mengalokasikan tumpukan pada tumpukan di setiap program, jadi mengapa tidak ada perangkat keras OS + yang melakukannya untuk Anda?
Jika Anda ingin segala sesuatunya menjadi sangat sederhana dan efisien, cukup berikan memori kepada pengguna dan biarkan mereka menanganinya. Tentu saja, tidak ada yang ingin menerapkan semuanya sendiri dan itulah sebabnya kami memiliki setumpuk dan tumpukan.
sumber
Diperlukan tumpukan dan tumpukan. Mereka digunakan dalam situasi yang berbeda, misalnya:
Pada dasarnya mekanisme tidak dapat dibandingkan sama sekali karena begitu banyak detail yang berbeda. Satu-satunya hal yang sama dengan mereka adalah bahwa mereka berdua menangani memori entah bagaimana.
sumber
Komputer modern memiliki beberapa lapisan memori cache selain sistem memori utama yang besar dan lambat. Satu dapat membuat lusinan akses ke memori cache tercepat dalam waktu yang diperlukan untuk membaca atau menulis satu byte dari sistem memori utama. Dengan demikian, mengakses satu lokasi seribu kali jauh lebih cepat daripada mengakses 1.000 (atau bahkan 100) lokasi independen masing-masing satu kali. Karena sebagian besar aplikasi berulang kali mengalokasikan dan membatalkan alokasi sejumlah kecil memori di dekat bagian atas tumpukan, lokasi di bagian atas tumpukan digunakan dan digunakan kembali dalam jumlah yang sangat besar, sehingga sebagian besar (99% + dalam aplikasi khas) akses stack dapat ditangani menggunakan memori cache.
Sebaliknya, jika suatu aplikasi berulang kali membuat dan meninggalkan objek tumpukan untuk menyimpan informasi kelanjutan, setiap versi dari setiap objek tumpukan yang pernah dibuat harus dituliskan ke memori utama. Bahkan jika sebagian besar objek tersebut akan sama sekali tidak berguna pada saat CPU ingin mendaur ulang halaman cache yang mereka mulai, CPU tidak akan memiliki cara untuk mengetahui hal itu. Akibatnya, CPU harus membuang banyak waktu melakukan memori lambat menulis informasi yang tidak berguna. Bukan resep untuk kecepatan.
Hal lain yang perlu dipertimbangkan adalah bahwa dalam banyak kasus, berguna untuk mengetahui bahwa referensi objek yang diteruskan ke rutin tidak akan digunakan setelah rutin keluar. Jika parameter dan variabel lokal dilewatkan melalui tumpukan, dan jika inspeksi kode rutin mengungkapkan bahwa itu tidak bertahan salinan referensi yang lewat, maka kode yang memanggil rutin dapat memastikan bahwa jika tidak ada referensi luar ke objek ada sebelum panggilan, tidak ada yang akan ada sesudahnya. Sebaliknya, jika parameter dilewatkan melalui objek tumpukan, konsep seperti "setelah pengembalian rutin" menjadi agak lebih samar, karena jika kode menyimpan salinan kelanjutan, akan mungkin bagi rutin untuk "kembali" lebih dari sekali mengikuti panggilan tunggal.
sumber