Buku-buku bahasa pemrograman menjelaskan bahwa tipe nilai dibuat di stack , dan tipe referensi dibuat di heap , tanpa menjelaskan apa dua hal ini. Saya belum membaca penjelasan yang jelas tentang ini. Saya mengerti apa itu stack . Tapi,
- Di mana dan apa mereka (secara fisik dalam memori komputer nyata)?
- Sejauh mana mereka dikendalikan oleh OS atau bahasa run-time?
- Apa ruang lingkup mereka?
- Apa yang menentukan ukuran masing-masing?
- Apa yang membuat seseorang lebih cepat?
rlimit_stack
. Lihat juga MasalahJawaban:
Tumpukan adalah memori yang disisihkan sebagai ruang awal untuk utas eksekusi. Ketika suatu fungsi dipanggil, sebuah blok dicadangkan di atas tumpukan untuk variabel lokal dan beberapa data pembukuan. Ketika fungsi itu kembali, blok menjadi tidak digunakan dan dapat digunakan saat suatu fungsi dipanggil. Tumpukan selalu dicadangkan dalam urutan LIFO (last in first out); blok yang paling baru dipesan selalu blok berikutnya yang akan dibebaskan. Ini membuatnya sangat sederhana untuk melacak tumpukan; membebaskan blok dari tumpukan tidak lebih dari menyesuaikan satu pointer.
Heap adalah memori yang disisihkan untuk alokasi dinamis. Berbeda dengan stack, tidak ada pola yang dipaksakan untuk alokasi dan deallokasi blok dari heap; Anda dapat mengalokasikan blok kapan saja dan membebaskannya kapan saja. Ini membuatnya jauh lebih kompleks untuk melacak bagian mana dari tumpukan yang dialokasikan atau gratis pada waktu tertentu; ada banyak pengalokasi tumpukan kustom yang tersedia untuk menyesuaikan kinerja tumpukan untuk pola penggunaan yang berbeda.
Setiap utas mendapat tumpukan, sementara biasanya hanya ada satu tumpukan untuk aplikasi (meskipun tidak jarang memiliki banyak tumpukan untuk berbagai jenis alokasi).
Untuk menjawab pertanyaan Anda secara langsung:
OS mengalokasikan tumpukan untuk setiap utas tingkat sistem saat utas dibuat. Biasanya OS dipanggil oleh runtime bahasa untuk mengalokasikan heap untuk aplikasi.
Tumpukan dilampirkan ke utas, jadi ketika utas keluar, tumpukan diambil kembali. Tumpukan biasanya dialokasikan pada startup aplikasi oleh runtime, dan direklamasi ketika aplikasi (secara teknis memproses) keluar.
Ukuran tumpukan diatur saat utas dibuat. Ukuran heap diatur pada startup aplikasi, tetapi dapat tumbuh sesuai ruang yang dibutuhkan (pengalokasi meminta lebih banyak memori dari sistem operasi).
Tumpukan lebih cepat karena pola akses membuatnya sepele untuk mengalokasikan dan membatalkan alokasi memori dari itu (pointer / integer hanya bertambah atau berkurang), sedangkan tumpukan memiliki pembukuan yang jauh lebih kompleks yang terlibat dalam alokasi atau deallokasi. Selain itu, setiap byte dalam tumpukan cenderung sering digunakan kembali yang artinya cenderung dipetakan ke cache prosesor, membuatnya sangat cepat. Hit kinerja lain untuk heap adalah heap, yang sebagian besar merupakan sumber daya global, biasanya harus multi-threading aman, yaitu setiap alokasi dan deallokasi harus - biasanya - disinkronkan dengan "semua" akses heap lain dalam program.
Demonstrasi yang jelas:
Sumber gambar: vikashazrati.wordpress.com
sumber
Tumpukan:
Tumpukan:
delete
,delete[]
ataufree
.new
ataumalloc
masing - masing.Contoh:
sumber
C
bahasa, sebagaimana didefinisikan olehC99
standar bahasa (tersedia di open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf ), memerlukan "tumpukan". Bahkan, kata 'tumpukan' bahkan tidak muncul dalam standar. Pernyataan ini menjawab wrt / toC
penggunaan stack benar secara umum, tetapi sama sekali tidak diperlukan oleh bahasa. Lihat knosof.co.uk/cbook/cbook.html untuk info lebih lanjut, dan khususnya bagaimanaC
diterapkan pada arsitektur ganjil seperti en.wikipedia.org/wiki/Burroughs_large_systemsPoin paling penting adalah bahwa tumpukan dan tumpukan adalah istilah umum untuk cara di mana memori dapat dialokasikan. Mereka dapat diimplementasikan dalam banyak cara yang berbeda, dan istilah ini berlaku untuk konsep dasar.
Dalam tumpukan item, item duduk satu di atas yang lain dalam urutan ditempatkan di sana, dan Anda hanya dapat menghapus yang atas (tanpa menjatuhkan semuanya).
Kesederhanaan tumpukan adalah bahwa Anda tidak perlu mempertahankan tabel yang berisi catatan setiap bagian dari memori yang dialokasikan; satu-satunya informasi negara yang Anda butuhkan adalah satu penunjuk ke ujung tumpukan. Untuk mengalokasikan dan menghapus alokasi, Anda hanya menambah dan mengurangi pointer tunggal itu. Catatan: tumpukan kadang-kadang dapat diimplementasikan untuk memulai di bagian atas dari memori dan memperluas ke bawah daripada tumbuh ke atas.
Dalam tumpukan, tidak ada urutan khusus untuk cara item ditempatkan. Anda dapat menjangkau dan menghapus item dalam urutan apa pun karena tidak ada item 'teratas' yang jelas.
Alokasi tumpukan memerlukan pemeliharaan catatan penuh dari memori yang dialokasikan dan apa yang tidak, serta beberapa pemeliharaan overhead untuk mengurangi fragmentasi, menemukan segmen memori yang berdekatan cukup besar agar sesuai dengan ukuran yang diminta, dan sebagainya. Memori dapat dibatalkan alokasinya kapan saja meninggalkan ruang kosong. Kadang-kadang pengalokasi memori akan melakukan tugas perawatan seperti mendefrag memori dengan memindahkan memori yang dialokasikan, atau mengumpulkan sampah - mengidentifikasi saat runtime ketika memori tidak lagi dalam ruang lingkup dan membatalkan alokasi.
Gambar-gambar ini harus melakukan pekerjaan yang cukup baik untuk menggambarkan dua cara mengalokasikan dan membebaskan memori dalam tumpukan dan tumpukan. Yum!
Sejauh mana mereka dikendalikan oleh runtime OS atau bahasa?
Seperti disebutkan, heap dan stack adalah istilah umum, dan dapat diimplementasikan dalam banyak cara. Program komputer biasanya memiliki tumpukan yang disebut tumpukan panggilan yang menyimpan informasi yang relevan dengan fungsi saat ini seperti pointer ke mana fungsi itu dipanggil, dan variabel lokal apa pun. Karena fungsi memanggil fungsi lain dan kemudian kembali, tumpukan tumbuh dan menyusut untuk menyimpan informasi dari fungsi lebih jauh ke tumpukan panggilan. Suatu program tidak benar-benar memiliki kontrol runtime atasnya; itu ditentukan oleh bahasa pemrograman, OS dan bahkan arsitektur sistem.
Heap adalah istilah umum yang digunakan untuk setiap memori yang dialokasikan secara dinamis dan acak; yaitu rusak. Memori biasanya dialokasikan oleh OS, dengan aplikasi yang memanggil fungsi API untuk melakukan alokasi ini. Ada sedikit overhead yang diperlukan dalam mengelola memori yang dialokasikan secara dinamis, yang biasanya ditangani oleh kode runtime dari bahasa pemrograman atau lingkungan yang digunakan.
Apa ruang lingkup mereka?
Tumpukan panggilan adalah konsep tingkat rendah sehingga tidak berhubungan dengan 'ruang lingkup' dalam arti pemrograman. Jika Anda membongkar beberapa kode, Anda akan melihat referensi gaya pointer relatif ke bagian-bagian stack, tetapi sejauh menyangkut bahasa tingkat yang lebih tinggi, bahasa tersebut memberlakukan aturan cakupannya sendiri. Namun, satu aspek penting dari stack adalah bahwa begitu suatu fungsi kembali, segala sesuatu yang bersifat lokal dari fungsi tersebut segera dibebaskan dari stack. Itu bekerja dengan cara yang Anda harapkan akan berfungsi mengingat cara kerja bahasa pemrograman Anda. Dalam tumpukan, juga sulit untuk didefinisikan. Cakupannya adalah apa pun yang diekspos oleh OS, tetapi bahasa pemrograman Anda mungkin menambahkan aturannya tentang apa "lingkup" dalam aplikasi Anda. Arsitektur prosesor dan OS menggunakan pengalamatan virtual, yang diterjemahkan oleh prosesor ke alamat fisik dan ada kesalahan halaman, dll. Mereka melacak halaman apa yang termasuk dalam aplikasi mana. Anda tidak pernah benar-benar perlu khawatir tentang ini, karena Anda hanya menggunakan metode apa pun yang digunakan bahasa pemrograman Anda untuk mengalokasikan dan membebaskan memori, dan memeriksa kesalahan (jika alokasi / pembebasan gagal karena alasan apa pun).
Apa yang menentukan ukuran masing-masing?
Sekali lagi, itu tergantung pada bahasa, kompiler, sistem operasi dan arsitektur. Tumpukan biasanya pra-dialokasikan, karena menurut definisi itu harus memori yang berdekatan. Kompilator bahasa atau OS menentukan ukurannya. Anda tidak menyimpan potongan besar data pada stack, jadi itu akan cukup besar sehingga tidak boleh sepenuhnya digunakan, kecuali dalam kasus rekursi tak berujung yang tidak diinginkan (karenanya, "stack overflow") atau keputusan pemrograman tidak biasa lainnya.
Tumpukan adalah istilah umum untuk apa pun yang dapat dialokasikan secara dinamis. Tergantung pada cara Anda melihatnya, ukurannya terus berubah. Dalam prosesor dan sistem operasi modern cara tepatnya cara kerjanya sangat abstrak, jadi Anda biasanya tidak perlu terlalu khawatir tentang cara kerjanya jauh di bawah, kecuali bahwa (dalam bahasa yang memungkinkan Anda), Anda tidak boleh menggunakan memori yang Anda belum mengalokasikan atau memori yang telah Anda bebaskan.
Apa yang membuat seseorang lebih cepat?
Tumpukan lebih cepat karena semua memori bebas selalu bersebelahan. Tidak ada daftar yang perlu dipertahankan dari semua segmen memori bebas, hanya satu penunjuk ke bagian atas tumpukan saat ini. Compiler biasanya menyimpan pointer ini dalam register khusus yang cepat untuk keperluan ini. Terlebih lagi, operasi selanjutnya pada stack biasanya terkonsentrasi di area memori yang sangat dekat, yang pada level yang sangat rendah baik untuk optimasi oleh cache on-die prosesor.
sumber
(Saya telah memindahkan jawaban ini dari pertanyaan lain yang kurang lebih merupakan jawaban dari pertanyaan ini.)
Jawaban untuk pertanyaan Anda adalah implementasi spesifik dan dapat bervariasi di seluruh kompiler dan arsitektur prosesor. Namun, inilah penjelasan yang disederhanakan.
Tumpukan itu
new
ataumalloc
) dipenuhi dengan membuat blok yang sesuai dari salah satu blok gratis. Ini membutuhkan pembaruan daftar blok pada heap. Informasi meta ini tentang blok di heap juga disimpan di heap sering di area kecil tepat di depan setiap blok.Tumpukan
Tidak, catatan aktivasi untuk fungsi (yaitu variabel lokal atau otomatis) dialokasikan pada tumpukan yang digunakan tidak hanya untuk menyimpan variabel-variabel ini, tetapi juga untuk melacak panggilan fungsi yang disarangkan.
Bagaimana tumpukan dikelola benar-benar hingga lingkungan runtime. Penggunaan C
malloc
dan penggunaan C ++new
, tetapi banyak bahasa lain memiliki pengumpulan sampah.Namun, stack adalah fitur tingkat rendah yang terkait erat dengan arsitektur prosesor. Menumbuhkan tumpukan ketika tidak ada cukup ruang tidak terlalu sulit karena dapat diimplementasikan dalam panggilan perpustakaan yang menangani tumpukan. Namun, menumbuhkan tumpukan seringkali tidak mungkin karena stack overflow hanya ditemukan ketika sudah terlambat; dan mematikan utas eksekusi adalah satu-satunya pilihan.
sumber
Dalam kode C # berikut
Begini cara memori dikelola
Local Variables
yang hanya perlu bertahan selama pemanggilan fungsi masuk ke stack. Heap digunakan untuk variabel yang seumur hidupnya kita tidak benar-benar tahu di muka tetapi kita berharap mereka bertahan lama. Dalam kebanyakan bahasa, penting bagi kita untuk mengetahui pada waktu kompilasi seberapa besar variabel jika kita ingin menyimpannya di stack.Objek (yang bervariasi dalam ukuran saat kita memperbaruinya) terus bertambah karena kita tidak tahu pada waktu pembuatan berapa lama mereka akan bertahan. Dalam banyak bahasa tumpukan adalah sampah yang dikumpulkan untuk menemukan objek (seperti objek cls1) yang tidak lagi memiliki referensi.
Di Jawa, sebagian besar objek masuk langsung ke tumpukan. Dalam bahasa seperti C / C ++, struct dan kelas seringkali dapat tetap berada di stack ketika Anda tidak berurusan dengan pointer.
Informasi lebih lanjut dapat ditemukan di sini:
Perbedaan antara tumpukan dan tumpukan memori alokasi «timmurphy.org
dan di sini:
Membuat Objek di Stack and Heap
Artikel ini adalah sumber gambar di atas: Enam konsep .NET penting: Stack, heap, tipe nilai, tipe referensi, tinju, dan unboxing - CodeProject
tapi ketahuilah itu mungkin mengandung beberapa ketidakakuratan.
sumber
Tumpukan Ketika Anda memanggil suatu fungsi argumen untuk fungsi itu ditambah beberapa overhead lainnya diletakkan di stack. Beberapa info (seperti tempat kembali) juga disimpan di sana. Ketika Anda mendeklarasikan variabel di dalam fungsi Anda, variabel itu juga dialokasikan pada stack.
Deallocating stack sangat sederhana karena Anda selalu melakukan deallocate dalam urutan terbalik yang Anda alokasikan. Stack stuff ditambahkan saat Anda memasukkan fungsi, data yang sesuai dihapus saat Anda keluar dari fungsinya. Ini berarti Anda cenderung tetap berada dalam wilayah kecil tumpukan kecuali jika Anda memanggil banyak fungsi yang memanggil banyak fungsi lainnya (atau membuat solusi rekursif).
Heap Heap adalah nama umum untuk tempat Anda meletakkan data yang Anda buat dengan cepat. Jika Anda tidak tahu berapa banyak pesawat ruang angkasa yang akan dibuat oleh program Anda, Anda cenderung menggunakan operator baru (atau malloc atau yang setara) untuk membuat setiap pesawat ruang angkasa. Alokasi ini akan bertahan sebentar, jadi kemungkinan kita akan membebaskan barang dalam urutan yang berbeda dari yang kita buat.
Dengan demikian, tumpukan jauh lebih kompleks, karena akhirnya ada daerah memori yang tidak terpakai disisipkan dengan potongan yang - memori menjadi terfragmentasi. Menemukan memori bebas dari ukuran yang Anda butuhkan adalah masalah yang sulit. Inilah mengapa tumpukan harus dihindari (meskipun masih sering digunakan).
Implementasi Implementasi stack dan heap biasanya turun ke runtime / OS. Seringkali gim dan aplikasi lain yang sangat penting kinerjanya membuat solusi memori mereka sendiri yang mengambil banyak memori dari tumpukan dan kemudian menyajikannya secara internal untuk menghindari mengandalkan OS untuk memori.
Ini hanya praktis jika penggunaan memori Anda sangat berbeda dari norma - yaitu untuk gim di mana Anda memuat level dalam satu operasi besar dan dapat membuang semuanya jauh dalam operasi besar lainnya.
Lokasi fisik dalam memori Ini kurang relevan daripada yang Anda pikirkan karena teknologi yang disebut Memori Virtual yang membuat program Anda berpikir bahwa Anda memiliki akses ke alamat tertentu di mana data fisik berada di tempat lain (bahkan di hard disk!). Alamat yang Anda dapatkan untuk tumpukan semakin meningkat saat pohon panggilan Anda semakin dalam. Alamat untuk heap tidak dapat diprediksi (yaitu spesifik implimentation) dan terus terang tidak penting.
sumber
Untuk memperjelas, jawaban ini memiliki informasi yang salah ( thomas memperbaiki jawabannya setelah komentar, keren :)). Jawaban lain hanya menghindari menjelaskan apa artinya alokasi statis. Jadi saya akan menjelaskan tiga bentuk alokasi utama dan bagaimana mereka biasanya berhubungan dengan heap, stack, dan segmen data di bawah ini. Saya juga akan menunjukkan beberapa contoh dalam C / C ++ dan Python untuk membantu orang mengerti.
Variabel "Statis" (AKA dialokasikan secara statis) tidak dialokasikan pada stack. Jangan berasumsi begitu - banyak orang melakukannya hanya karena "statis" terdengar sangat mirip "tumpukan". Mereka sebenarnya tidak ada di tumpukan atau tumpukan. Merupakan bagian dari apa yang disebut segmen data .
Namun, umumnya lebih baik untuk mempertimbangkan " ruang lingkup " dan " seumur hidup " daripada "tumpukan" dan "tumpukan".
Lingkup mengacu pada bagian mana dari kode yang dapat mengakses variabel. Secara umum kami berpikir tentang ruang lingkup lokal (hanya dapat diakses oleh fungsi saat ini) versus ruang lingkup global (dapat diakses di mana saja) meskipun ruang lingkup bisa menjadi jauh lebih kompleks.
Seumur hidup mengacu pada ketika variabel dialokasikan dan dialokasikan selama pelaksanaan program. Biasanya kami memikirkan alokasi statis (variabel akan bertahan selama seluruh durasi program, sehingga berguna untuk menyimpan informasi yang sama di beberapa panggilan fungsi) versus alokasi otomatis (variabel hanya bertahan selama satu panggilan ke suatu fungsi, sehingga berguna untuk menyimpan informasi yang hanya digunakan selama fungsi Anda dan dapat dibuang setelah Anda selesai) versus alokasi dinamis (variabel yang durasinya ditentukan saat runtime, alih-alih waktu kompilasi seperti statis atau otomatis).
Meskipun sebagian besar kompiler dan interpreter menerapkan perilaku ini secara serupa dalam hal menggunakan tumpukan, tumpukan, dll, kompiler kadang-kadang dapat melanggar konvensi ini jika ingin selama perilaku itu benar. Misalnya, karena optimasi, variabel lokal hanya dapat ada dalam register atau dihapus seluruhnya, meskipun sebagian besar variabel lokal ada di tumpukan. Seperti yang telah ditunjukkan dalam beberapa komentar, Anda bebas menerapkan kompiler yang bahkan tidak menggunakan stack atau heap, tetapi beberapa mekanisme penyimpanan lainnya (jarang dilakukan, karena tumpukan dan tumpukan sangat bagus untuk ini).
Saya akan memberikan beberapa kode C beranotasi sederhana untuk menggambarkan semua ini. Cara terbaik untuk belajar adalah menjalankan program di bawah debugger dan melihat perilaku tersebut. Jika Anda lebih suka membaca python, lewati sampai akhir jawaban :)
Contoh yang sangat tajam tentang mengapa penting untuk membedakan antara masa hidup dan ruang lingkup adalah bahwa variabel dapat memiliki ruang lingkup lokal tetapi seumur hidup statis - misalnya, "someLocalStaticVariable" dalam contoh kode di atas. Variabel-variabel semacam itu dapat membuat kebiasaan penamaan kita yang umum tetapi tidak resmi sangat membingungkan. Sebagai contoh ketika kita mengatakan " lokal " kita biasanya berarti " variabel yang dialokasikan secara otomatis secara lokal " dan ketika kita mengatakan global kita biasanya berarti " variabel yang dialokasikan secara global dengan cakupan statis ". Sayangnya ketika datang ke hal-hal seperti " file scoped variabel yang dialokasikan secara statis " banyak orang hanya mengatakan ... " huh ??? ".
Beberapa pilihan sintaks dalam C / C ++ memperburuk masalah ini - misalnya banyak orang berpikir variabel global tidak "statis" karena sintaks yang ditunjukkan di bawah ini.
Perhatikan bahwa menempatkan kata kunci "statis" dalam deklarasi di atas mencegah var2 memiliki lingkup global. Namun demikian, global var1 memiliki alokasi statis. Ini tidak intuitif! Untuk alasan ini, saya mencoba untuk tidak pernah menggunakan kata "statis" ketika menggambarkan ruang lingkup, dan sebaliknya mengatakan sesuatu seperti ruang lingkup "file" atau "file terbatas". Namun banyak orang menggunakan frasa "statis" atau "ruang lingkup statis" untuk menggambarkan variabel yang hanya dapat diakses dari satu file kode. Dalam konteks seumur hidup, "statis" selalu berarti variabel dialokasikan pada awal program dan tidak dialokasikan ketika program keluar.
Beberapa orang menganggap konsep ini spesifik untuk C / C ++. Mereka tidak. Sebagai contoh, contoh Python di bawah ini menggambarkan ketiga jenis alokasi (ada beberapa perbedaan halus dalam bahasa yang ditafsirkan yang tidak akan saya bahas di sini).
sumber
PostScript
memiliki banyak tumpukan, tetapi memiliki "tumpukan" yang berperilaku lebih seperti tumpukan.Yang lain telah menjawab sapuan luas dengan cukup baik, jadi saya akan memberikan beberapa detail.
Stack dan heap tidak harus tunggal. Situasi umum di mana Anda memiliki lebih dari satu tumpukan adalah jika Anda memiliki lebih dari satu utas dalam suatu proses. Dalam hal ini setiap utas memiliki tumpukan sendiri. Anda juga dapat memiliki lebih dari satu tumpukan, misalnya beberapa konfigurasi DLL dapat mengakibatkan alokasi DLL yang berbeda dari tumpukan yang berbeda, itulah sebabnya mengapa itu adalah ide yang buruk untuk melepaskan memori yang dialokasikan oleh perpustakaan yang berbeda.
Dalam C Anda bisa mendapatkan manfaat dari alokasi panjang variabel melalui penggunaan alokasi , yang mengalokasikan pada tumpukan, sebagai lawan alokasi, yang mengalokasikan pada heap. Memori ini tidak akan bertahan dari pernyataan pengembalian Anda, tetapi ini berguna untuk buffer awal.
Membuat buffer sementara yang besar di Windows yang tidak Anda gunakan tidak gratis. Ini karena kompiler akan menghasilkan loop probe stack yang dipanggil setiap kali fungsi Anda dimasukkan untuk memastikan stack ada (karena Windows menggunakan halaman penjaga tunggal di ujung tumpukan Anda untuk mendeteksi kapan perlu menumbuhkan tumpukan. Jika Anda mengakses memori lebih dari satu halaman dari ujung tumpukan Anda akan crash). Contoh:
sumber
alloca
?Orang lain secara langsung menjawab pertanyaan Anda, tetapi ketika mencoba memahami tumpukan dan tumpukan, saya pikir akan membantu untuk mempertimbangkan tata letak memori dari proses UNIX tradisional (tanpa thread dan
mmap()
pengalokasi berbasis-basis). The Memory Management Glosarium halaman web memiliki diagram tata letak memori ini.Tumpukan dan tumpukan secara tradisional terletak di ujung yang berlawanan dari ruang alamat virtual proses. Tumpukan tumbuh secara otomatis saat diakses, hingga ukuran yang ditentukan oleh kernel (yang dapat disesuaikan dengan
setrlimit(RLIMIT_STACK, ...)
). Tumpukan tumbuh ketika pengalokasi memori memanggilbrk()
atausbrk()
system call, memetakan lebih banyak halaman memori fisik ke dalam ruang alamat virtual proses.Dalam sistem tanpa memori virtual, seperti beberapa sistem tertanam, tata letak dasar yang sama sering berlaku, kecuali tumpukan dan tumpukan diperbaiki dalam ukuran. Namun, dalam sistem tertanam lainnya (seperti yang berbasis pada mikrokontroler PIC Microchip), tumpukan program adalah blok memori terpisah yang tidak dapat dialamatkan oleh instruksi perpindahan data, dan hanya dapat dimodifikasi atau dibaca secara tidak langsung melalui instruksi aliran program (panggilan, kembali, dll.). Arsitektur lain, seperti prosesor Intel Itanium, memiliki banyak tumpukan . Dalam pengertian ini, tumpukan adalah elemen arsitektur CPU.
sumber
Apa itu tumpukan?
Tumpukan adalah tumpukan benda, biasanya yang tertata rapi.
Apa itu heap?
Tumpukan adalah kumpulan benda-benda yang tertumpuk secara acak.
Berdua bersama
Mana yang lebih cepat - tumpukan atau tumpukan? Dan mengapa?
Untuk orang yang baru dalam pemrograman, mungkin ide yang baik untuk menggunakan stack karena lebih mudah.
Karena tumpukannya kecil, Anda ingin menggunakannya ketika Anda tahu persis berapa banyak memori yang Anda perlukan untuk data Anda, atau jika Anda tahu ukuran data Anda sangat kecil.
Lebih baik menggunakan heap ketika Anda tahu bahwa Anda akan membutuhkan banyak memori untuk data Anda, atau Anda hanya tidak yakin berapa banyak memori yang akan Anda butuhkan (seperti dengan array dinamis).
Model Memori Java
Tumpukan adalah area memori tempat variabel lokal (termasuk parameter metode) disimpan. Ketika datang ke variabel objek, ini hanyalah referensi (pointer) ke objek aktual di heap.
Setiap kali suatu objek dipakai, sepotong memori tumpukan disisihkan untuk menyimpan data (keadaan) objek itu. Karena objek dapat berisi objek lain, beberapa data ini sebenarnya bisa menyimpan referensi ke objek bersarang.
sumber
Tumpukan adalah bagian dari memori yang dapat dimanipulasi melalui beberapa instruksi bahasa rakitan kunci, seperti 'pop' (menghapus dan mengembalikan nilai dari tumpukan) dan 'mendorong' (mendorong nilai ke tumpukan), tetapi juga memanggil ( panggil subrutin - ini mendorong alamat untuk kembali ke tumpukan) dan kembali (kembali dari subrutin - ini memunculkan alamat dari tumpukan dan melompat ke sana). Ini adalah wilayah memori di bawah register penunjuk tumpukan, yang dapat diatur sesuai kebutuhan. Tumpukan juga digunakan untuk meneruskan argumen ke subrutin, dan juga untuk menjaga nilai dalam register sebelum memanggil subrutin.
Tumpukan adalah sebagian dari memori yang diberikan kepada aplikasi oleh sistem operasi, biasanya melalui syscall seperti malloc. Pada OS modern, memori ini adalah sekumpulan halaman yang hanya dapat diakses oleh proses panggilan.
Ukuran tumpukan ditentukan saat runtime, dan umumnya tidak tumbuh setelah program diluncurkan. Dalam program C, tumpukan harus cukup besar untuk menampung setiap variabel yang dideklarasikan dalam setiap fungsi. Tumpukan akan tumbuh secara dinamis sesuai kebutuhan, tetapi OS akhirnya membuat panggilan (sering akan menumpuk lebih dari nilai yang diminta oleh malloc, sehingga setidaknya beberapa mallocs di masa depan tidak perlu kembali ke kernel untuk dapatkan lebih banyak memori. Perilaku ini sering kali dapat disesuaikan)
Karena Anda telah mengalokasikan stack sebelum meluncurkan program, Anda tidak perlu melakukan malloc sebelum Anda dapat menggunakan stack, jadi itu sedikit keuntungan di sana. Dalam praktiknya, sangat sulit untuk memprediksi apa yang akan cepat dan apa yang akan lambat dalam sistem operasi modern yang memiliki subsistem memori virtual, karena bagaimana halaman diimplementasikan dan di mana mereka disimpan adalah detail implementasi.
sumber
Saya pikir banyak orang telah memberi Anda jawaban yang benar tentang masalah ini.
Namun, satu detail yang terlewatkan adalah "tumpukan" itu sebenarnya mungkin disebut "toko gratis". Alasan untuk perbedaan ini adalah bahwa toko bebas asli diimplementasikan dengan struktur data yang dikenal sebagai "tumpukan binomial." Karena alasan itu, pengalokasian dari implementasi awal malloc () / free () adalah alokasi dari heap. Namun, di zaman modern ini, sebagian besar toko gratis diimplementasikan dengan struktur data yang sangat rumit yang bukan tumpukan binomial.
sumber
C
bahasa. Ini adalah kesalahpahaman umum, meskipun itu adalah (sejauh) mendominasi paradigma untuk implementasiC99 6.2.4 automatic storage duration objects
(variabel). Bahkan, kata "tumpukan" bahkan tidak muncul dalamC99
standar bahasa: open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdfAnda dapat melakukan beberapa hal menarik dengan tumpukan. Misalnya, Anda memiliki fungsi seperti Alokasi (dengan asumsi Anda bisa melewati peringatan berlebihan tentang penggunaannya), yang merupakan bentuk malloc yang secara khusus menggunakan stack, bukan heap, untuk memori.
Yang mengatakan, kesalahan memori berbasis stack adalah beberapa yang terburuk yang pernah saya alami. Jika Anda menggunakan memori tumpukan, dan Anda melampaui batas blok yang dialokasikan, Anda memiliki peluang yang layak untuk memicu kesalahan segmen. (Tidak 100%: blok Anda mungkin berdekatan dengan yang lain yang sebelumnya Anda alokasikan). Tetapi karena variabel yang dibuat pada tumpukan selalu berdekatan satu sama lain, penulisan di luar batas dapat mengubah nilai variabel lain. Saya telah belajar bahwa setiap kali saya merasa bahwa program saya telah berhenti mematuhi hukum logika, itu mungkin buffer overflow.
sumber
alloca
? Misalnya, apakah ini berfungsi pada Windows? Apakah hanya untuk sistem operasi mirip Unix?Secara sederhana, stack adalah tempat variabel lokal dibuat. Juga, setiap kali Anda memanggil subrutin penghitung program (penunjuk ke instruksi mesin berikutnya) dan register penting apa pun, dan terkadang parameter didorong pada tumpukan. Kemudian setiap variabel lokal di dalam subrutin didorong ke stack (dan digunakan dari sana). Ketika subrutin selesai, semua itu akan muncul kembali dari tumpukan. PC dan mendaftar data didapat dan dimasukkan kembali ke tempatnya semula, sehingga program Anda dapat berjalan dengan cara yang menyenangkan.
Heap adalah area alokasi memori dinamis yang terbuat dari memori (panggilan "baru" atau "alokasikan" eksplisit). Ini adalah struktur data khusus yang dapat melacak blok memori dengan berbagai ukuran dan status alokasi mereka.
Dalam sistem "klasik", RAM diletakkan sedemikian rupa sehingga penumpukan tumpukan dimulai di bagian bawah memori, penumpukan tumpukan dimulai di bagian atas, dan mereka tumbuh saling berhadapan. Jika tumpang tindih, Anda kehabisan RAM. Itu tidak bekerja dengan OS multi-threaded modern sekalipun. Setiap utas harus memiliki tumpukan sendiri, dan itu dapat dibuat secara dinamis.
sumber
Dari WikiAnwser.
Tumpukan
Ketika suatu fungsi atau metode memanggil fungsi lain yang pada gilirannya memanggil fungsi lain, dll., Pelaksanaan semua fungsi tersebut tetap ditunda sampai fungsi terakhir mengembalikan nilainya.
Rantai panggilan fungsi yang ditangguhkan ini adalah tumpukan, karena elemen-elemen dalam tumpukan (panggilan fungsi) saling bergantung.
Tumpukan penting untuk dipertimbangkan dalam penanganan pengecualian dan eksekusi ulir.
Tumpukan
Heap hanyalah memori yang digunakan oleh program untuk menyimpan variabel. Elemen heap (variabel) tidak memiliki ketergantungan satu sama lain dan selalu dapat diakses secara acak kapan saja.
sumber
Tumpukan
Tumpukan
sumber
OK, sederhana dan dalam kata-kata singkat, itu berarti dipesan dan tidak dipesan ...!
Stack : Dalam tumpukan item, segalanya saling terkait, artinya akan lebih cepat dan lebih efisien untuk diproses! ...
Jadi selalu ada indeks untuk menunjuk item tertentu, juga pemrosesan akan lebih cepat, ada hubungan antara item juga! ...
Heap : Tidak ada pesanan, pemrosesan akan lebih lambat dan nilai-nilai kacau bersama tanpa urutan atau indeks tertentu ... ada acak dan tidak ada hubungan di antara mereka ... sehingga waktu eksekusi dan penggunaan dapat bervariasi ...
Saya juga membuat gambar di bawah ini untuk menunjukkan bagaimana tampilannya:
sumber
Pendeknya
Tumpukan digunakan untuk alokasi memori statis dan tumpukan untuk alokasi memori dinamis, keduanya disimpan dalam RAM komputer.
Secara terperinci
Tumpukan
Tumpukan adalah struktur data "LIFO" (last in, first out), yang dikelola dan dioptimalkan oleh CPU dengan cukup dekat. Setiap kali suatu fungsi mendeklarasikan variabel baru, ia "didorong" ke stack. Kemudian setiap kali suatu fungsi keluar, semua variabel yang didorong ke stack oleh fungsi itu, dibebaskan (artinya, mereka dihapus). Setelah variabel tumpukan dibebaskan, wilayah memori tersebut menjadi tersedia untuk variabel tumpukan lainnya.
Keuntungan menggunakan stack untuk menyimpan variabel, adalah memori dikelola untuk Anda. Anda tidak perlu mengalokasikan memori dengan tangan, atau membebaskannya setelah Anda tidak membutuhkannya lagi. Terlebih lagi, karena CPU mengatur memori tumpukan dengan sangat efisien, membaca dari dan menulis ke variabel tumpukan sangat cepat.
Lebih banyak dapat ditemukan di sini .
Heap
Tumpukan adalah wilayah memori komputer Anda yang tidak dikelola secara otomatis untuk Anda, dan tidak begitu ketat dikelola oleh CPU. Ini adalah wilayah memori yang lebih bebas mengambang (dan lebih besar). Untuk mengalokasikan memori pada heap, Anda harus menggunakan malloc () atau calloc (), yang merupakan fungsi C bawaan. Setelah Anda mengalokasikan memori pada heap, Anda bertanggung jawab untuk menggunakan free () untuk membatalkan alokasi memori setelah Anda tidak membutuhkannya lagi.
Jika Anda gagal melakukan ini, program Anda akan memiliki apa yang dikenal sebagai kebocoran memori. Artinya, memori pada heap masih akan disisihkan (dan tidak akan tersedia untuk proses lain). Seperti yang akan kita lihat di bagian debugging, ada alat bernama Valgrind yang dapat membantu Anda mendeteksi kebocoran memori.
Berbeda dengan stack, heap tidak memiliki batasan ukuran pada ukuran variabel (terlepas dari batasan fisik komputer Anda). Memori tumpukan sedikit lebih lambat untuk dibaca dan ditulis, karena kita harus menggunakan pointer untuk mengakses memori pada tumpukan. Kami akan segera berbicara tentang petunjuk.
Berbeda dengan stack, variabel yang dibuat di heap dapat diakses oleh fungsi apa saja, di mana saja di program Anda. Variabel tumpukan pada dasarnya bersifat global.
Lebih banyak dapat ditemukan di sini .
Variabel yang dialokasikan pada tumpukan disimpan langsung ke memori dan akses ke memori ini sangat cepat, dan alokasi tersebut ditangani ketika program dikompilasi. Ketika suatu fungsi atau metode memanggil fungsi lain yang pada gilirannya memanggil fungsi lain, dll., Pelaksanaan semua fungsi tersebut tetap ditunda sampai fungsi terakhir mengembalikan nilainya. Tumpukan selalu dicadangkan dalam urutan LIFO, blok yang paling terakhir dipesan selalu blok berikutnya yang akan dibebaskan. Ini membuatnya sangat sederhana untuk melacak tumpukan, membebaskan blok dari tumpukan tidak lebih dari menyesuaikan satu pointer.
Variabel yang dialokasikan pada heap memiliki alokasi memori pada saat run time dan mengakses memori ini sedikit lebih lambat, tetapi ukuran heap hanya dibatasi oleh ukuran memori virtual. Elemen tumpukan tidak memiliki ketergantungan satu sama lain dan selalu dapat diakses secara acak kapan saja. Anda dapat mengalokasikan blok kapan saja dan membebaskannya kapan saja. Ini membuatnya jauh lebih kompleks untuk melacak bagian mana dari tumpukan yang dialokasikan atau gratis pada waktu tertentu.
Anda dapat menggunakan tumpukan jika Anda tahu persis berapa banyak data yang perlu Anda alokasikan sebelum waktu kompilasi, dan itu tidak terlalu besar. Anda dapat menggunakan tumpukan jika Anda tidak tahu persis berapa banyak data yang akan Anda butuhkan saat runtime atau jika Anda perlu mengalokasikan banyak data.
Dalam situasi multi-utas, masing-masing utas akan memiliki tumpukan mandiri sepenuhnya, tetapi mereka akan berbagi tumpukan. Tumpukan adalah utas khusus dan tumpukan adalah spesifik aplikasi. Tumpukan penting untuk dipertimbangkan dalam penanganan pengecualian dan eksekusi ulir.
Setiap utas mendapat tumpukan, sementara biasanya hanya ada satu tumpukan untuk aplikasi (meskipun tidak jarang memiliki banyak tumpukan untuk berbagai jenis alokasi).
Pada saat run-time, jika aplikasi membutuhkan lebih banyak tumpukan, ia dapat mengalokasikan memori dari memori bebas dan jika stack membutuhkan memori, ia dapat mengalokasikan memori dari memori yang dialokasikan memori bebas untuk aplikasi tersebut.
Bahkan, lebih banyak detail diberikan di sini dan di sini .
Sekarang datang ke jawaban pertanyaan Anda .
OS mengalokasikan tumpukan untuk setiap utas tingkat sistem saat utas dibuat. Biasanya OS dipanggil oleh runtime bahasa untuk mengalokasikan heap untuk aplikasi.
Lebih banyak dapat ditemukan di sini .
Sudah diberikan di atas.
Lebih banyak dapat ditemukan di sini .
Ukuran tumpukan diatur oleh OS saat utas dibuat. Ukuran heap diatur pada startup aplikasi, tetapi bisa bertambah sesuai ruang yang dibutuhkan (pengalokasi meminta lebih banyak memori dari sistem operasi).
Alokasi tumpukan jauh lebih cepat karena yang dilakukannya hanyalah memindahkan penunjuk tumpukan. Menggunakan kumpulan memori, Anda bisa mendapatkan kinerja yang sebanding dari alokasi tumpukan, tetapi itu datang dengan sedikit kompleksitas tambahan dan sakit kepala sendiri.
Juga, tumpukan vs tumpukan tidak hanya pertimbangan kinerja; itu juga memberi tahu Anda banyak tentang umur objek yang diharapkan.
Detail dapat ditemukan dari sini .
sumber
Pada 1980-an, UNIX berkembang biak seperti kelinci dengan perusahaan besar menggulirkannya sendiri. Exxon memiliki satu seperti puluhan nama merek yang hilang karena sejarah. Bagaimana memori diletakkan adalah atas kebijaksanaan banyak pelaksana.
Sebuah program C yang umum diletakkan dalam memori datar dengan peluang untuk meningkat dengan mengubah nilai brk (). Biasanya, HEAP tepat di bawah nilai brk ini dan meningkatkan brk meningkatkan jumlah tumpukan yang tersedia.
STACK tunggal biasanya merupakan area di bawah HEAP yang merupakan saluran memori yang tidak mengandung nilai apa pun sampai bagian atas blok memori tetap berikutnya. Blok berikut ini seringkali adalah KODE yang dapat ditimpa oleh tumpukan data di salah satu peretasan terkenal di masanya.
Satu blok memori yang khas adalah BSS (blok bernilai nol) yang secara tidak sengaja tidak memusatkan perhatian pada penawaran satu produsen. Lainnya adalah DATA yang berisi nilai yang diinisialisasi, termasuk string dan angka. Yang ketiga adalah CODE yang mengandung CRT (C runtime), utama, fungsi, dan perpustakaan.
Munculnya memori virtual di UNIX mengubah banyak kendala. Tidak ada alasan obyektif mengapa blok-blok ini perlu bersebelahan, atau tetap dalam ukuran, atau dipesan dengan cara tertentu sekarang. Tentu saja, sebelum UNIX adalah Multics yang tidak menderita kendala ini. Berikut adalah skema yang menunjukkan salah satu tata letak memori era itu.
sumber
tumpukan , tumpukan dan data dari setiap proses dalam memori virtual:
sumber
Beberapa sen: Saya pikir, akan lebih baik untuk menggambar memori grafis dan lebih sederhana:
Panah - menunjukkan tempat tumbuhnya tumpukan dan tumpukan, proses ukuran tumpukan memiliki batas, ditentukan dalam OS, batas ukuran tumpukan benang dengan parameter dalam pembuatan API biasanya. Heap biasanya dibatasi oleh proses ukuran memori virtual maksimum, misalnya 32 bit 2-4 GB.
Jadi cara sederhana: tumpukan proses adalah umum untuk proses dan semua utas di dalamnya, gunakan untuk alokasi memori dalam kasus umum dengan sesuatu seperti malloc () .
Stack adalah memori cepat untuk menyimpan dalam fungsi umum pointer dan variabel pengembalian, diproses sebagai parameter dalam panggilan fungsi, variabel fungsi lokal.
sumber
Karena beberapa jawaban menjadi rewel, saya akan berkontribusi tungau saya.
Anehnya, tidak ada yang menyebutkan bahwa banyak (mis. Tidak terkait dengan jumlah menjalankan thread tingkat OS) tumpukan panggilan dapat ditemukan tidak hanya dalam bahasa eksotis (PostScript) atau platform (Intel Itanium), tetapi juga dalam serat , benang hijau dan beberapa implementasi coroutine .
Serat, benang hijau, dan coroutine dalam banyak hal serupa, yang menyebabkan banyak kebingungan. Perbedaan antara serat dan benang hijau adalah bahwa yang pertama menggunakan multitasking kooperatif, sedangkan yang kedua mungkin memiliki fitur kooperatif atau preemptive (atau bahkan keduanya). Untuk perbedaan antara serat dan coroutine, lihat di sini .
Bagaimanapun, tujuan dari kedua serat, benang hijau dan coroutine adalah memiliki beberapa fungsi yang dijalankan secara bersamaan, tetapi tidak secara paralel (lihat pertanyaan SO untuk perbedaan ini) dalam satu thread level OS tunggal, mentransfer kontrol bolak-balik satu sama lain secara terorganisir.
Saat menggunakan serat, benang hijau atau coroutine, Anda biasanya memiliki tumpukan terpisah per fungsi. (Secara teknis, bukan hanya setumpuk tetapi seluruh konteks eksekusi adalah per fungsi. Yang paling penting, register CPU.) Untuk setiap utas ada tumpukan yang sama banyaknya dengan fungsi yang sedang berjalan secara bersamaan, dan utas tersebut beralih antara menjalankan setiap fungsi sesuai dengan logika program Anda. Ketika suatu fungsi berjalan ke ujungnya, tumpukannya dihancurkan. Jadi, jumlah dan masa hidup tumpukan adalah dinamis dan tidak ditentukan oleh jumlah utas tingkat OS!
Perhatikan bahwa saya berkata " biasanya memiliki stack per fungsi yang terpisah". Ada implementasi stackoutine stackless dan stackless. Paling penting stackful C ++ implementasi yang Boost.Coroutine dan Microsoft PPL 's . (Namun, fungsi resume C ++ (alias " dan "), yang diusulkan ke C ++ 17, kemungkinan akan menggunakan coroutine stackless.)
async/await
async
await
Proposal serat ke pustaka standar C ++ akan hadir. Juga, ada beberapa perpustakaan pihak ketiga . Utas hijau sangat populer dalam bahasa seperti Python dan Ruby.
sumber
Saya memiliki sesuatu untuk dibagikan, meskipun poin utama sudah dibahas.
Tumpukan
Tumpukan
Catatan menarik:
sumber
Wow! Begitu banyak jawaban dan saya rasa salah satu dari mereka tidak benar ...
1) Di mana dan apa mereka (secara fisik dalam memori komputer nyata)?
Tumpukan adalah memori yang dimulai sebagai alamat memori tertinggi yang dialokasikan untuk gambar program Anda, dan kemudian berkurang nilainya dari sana. Ini dicadangkan untuk parameter fungsi yang disebut dan untuk semua variabel sementara yang digunakan dalam fungsi.
Ada dua tumpukan: publik dan pribadi.
Tumpukan pribadi dimulai pada batas 16-byte (untuk program 64-bit) atau batas 8-byte (untuk program 32-bit) setelah kode byte terakhir dalam program Anda, dan kemudian meningkat nilainya dari sana. Ini juga disebut heap default.
Jika tumpukan pribadi menjadi terlalu besar itu akan tumpang tindih area tumpukan, seperti tumpukan akan tumpang tindih tumpukan jika terlalu besar. Karena tumpukan dimulai dari alamat yang lebih tinggi dan berjalan turun ke alamat yang lebih rendah, dengan peretasan yang tepat Anda bisa membuat tumpukan itu begitu besar sehingga akan membanjiri area tumpukan pribadi dan menumpuk area kode. Triknya adalah tumpang tindih dengan area kode yang dapat Anda kaitkan ke dalam kode. Agak sulit untuk dilakukan dan Anda berisiko crash program, tetapi mudah dan sangat efektif.
Tumpukan publik berada di ruang memori itu sendiri di luar ruang gambar program Anda. Memori inilah yang akan disedot ke hard disk jika sumber daya memori menjadi langka.
2) Sejauh mana mereka dikendalikan oleh runtime OS atau bahasa?
Tumpukan dikendalikan oleh programmer, tumpukan pribadi dikelola oleh OS, dan tumpukan publik tidak dikendalikan oleh siapa pun karena ini adalah layanan OS - Anda membuat permintaan dan apakah itu diberikan atau ditolak.
2b) Apa cakupannya?
Semuanya bersifat global untuk program ini, tetapi isinya dapat bersifat pribadi, publik, atau global.
2c) Apa yang menentukan ukuran masing-masing?
Ukuran tumpukan dan tumpukan pribadi ditentukan oleh opsi runtime kompiler Anda. Tumpukan publik diinisialisasi pada saat runtime menggunakan parameter ukuran.
2d) Apa yang membuatnya lebih cepat?
Mereka tidak dirancang untuk menjadi cepat, mereka dirancang untuk berguna. Bagaimana programmer menggunakannya menentukan apakah mereka "cepat" atau "lambat"
REF:
https://norasandler.com/2019/02/18/Write-a-Compiler-10.html
https://docs.microsoft.com/en-us/windows/desktop/api/heapapi/nf-heapapi-getprocessheap
https://docs.microsoft.com/en-us/windows/desktop/api/heapapi/nf-heapapi-heapcreate
sumber
Banyak jawaban yang benar sebagai konsep, tetapi kita harus mencatat bahwa setumpuk diperlukan oleh perangkat keras (yaitu mikroprosesor) untuk memungkinkan memanggil subrutin (CALL dalam bahasa assembly ..). (OOP guys akan menyebutnya metode )
Pada tumpukan Anda menyimpan alamat kembali dan panggilan → push / ret → pop dikelola langsung di perangkat keras.
Anda dapat menggunakan tumpukan untuk melewatkan parameter .. bahkan jika itu lebih lambat daripada menggunakan register (akankah seorang guru mikroprosesor mengatakan atau buku BIOS 1980-an yang bagus ...)
Penggunaan tumpukan lebih cepat karena:
sumber
malloc
adalah panggilan kernel?Sumber: Academind
sumber
Terima kasih atas diskusi yang sangat baik tetapi sebagai noob nyata saya bertanya-tanya di mana instruksi disimpan? Dalam AWAL para ilmuwan memutuskan antara dua arsitektur (von NEUMANN di mana semuanya dianggap DATA dan HARVARD di mana area memori dicadangkan untuk instruksi dan yang lainnya untuk data). Pada akhirnya, kami menggunakan desain von Neumann dan sekarang semuanya dianggap 'sama'. Ini menyulitkan saya ketika saya sedang belajar perakitan https://www.cs.virginia.edu/~evans/cs216/guides/x86.html karena mereka berbicara tentang register dan penunjuk tumpukan.
Segala sesuatu di atas berbicara tentang DATA. Dugaan saya adalah bahwa karena instruksi adalah sesuatu yang didefinisikan dengan jejak memori tertentu, itu akan masuk ke tumpukan dan jadi semua register 'yang' dibahas dalam perakitan ada di tumpukan. Tentu saja kemudian datang pemrograman berorientasi objek dengan instruksi dan data yang muncul ke dalam struktur yang dinamis jadi sekarang instruksi akan disimpan di heap juga?
sumber