Saya telah memprogram untuk sementara waktu tetapi sebagian besar sudah Java dan C #. Saya tidak pernah benar-benar harus mengelola ingatan saya sendiri. Saya baru-baru ini mulai pemrograman dalam C ++ dan saya agak bingung kapan saya harus menyimpan sesuatu di stack dan kapan harus menyimpannya di heap.
Pemahaman saya adalah bahwa variabel yang sangat sering diakses harus disimpan di tumpukan dan objek, variabel yang jarang digunakan, dan struktur data yang besar semuanya harus disimpan di heap. Apakah ini benar atau saya salah?
Jawaban:
Tidak, perbedaan antara tumpukan dan heap bukanlah performa. Umurnya: variabel lokal apa pun di dalam fungsi (apa pun yang tidak Anda malloc () atau baru) tinggal di tumpukan. Ini hilang ketika Anda kembali dari fungsi. Jika Anda ingin sesuatu berdurasi lebih lama dari fungsi yang mendeklarasikannya, Anda harus mengalokasikannya di heap.
Untuk pemahaman yang lebih jelas tentang apa itu tumpukan, lihat dari ujung yang lain - daripada mencoba memahami apa yang dilakukan tumpukan dalam hal bahasa tingkat tinggi, cari "tumpukan panggilan" dan "konvensi pemanggilan" dan lihat apa mesin benar-benar melakukannya saat Anda memanggil suatu fungsi. Memori komputer hanyalah serangkaian alamat; "heap" dan "stack" adalah penemuan kompilator.
sumber
Saya akan mengatakan:
Simpan di tumpukan, jika Anda BISA.
Simpan di heap, jika PERLU.
Oleh karena itu, lebih suka tumpukan daripada heap. Beberapa kemungkinan alasan Anda tidak dapat menyimpan sesuatu di tumpukan adalah:
Hal ini dimungkinkan, dengan kompiler yang masuk akal, untuk mengalokasikan objek berukuran tidak tetap pada heap (biasanya array yang ukurannya tidak diketahui pada waktu kompilasi).
sumber
Ini lebih halus daripada yang disarankan oleh jawaban lain. Tidak ada pemisahan mutlak antara data di tumpukan dan data di heap berdasarkan cara Anda mendeklarasikannya. Sebagai contoh:
Dalam tubuh suatu fungsi, yang menyatakan a
vector
(larik dinamis) dari sepuluh bilangan bulat di tumpukan. Namun penyimpanannya dikelola olehvector
tidak ada di tumpukan.Ah, tapi (jawaban lain menyarankan) masa penyimpanan itu dibatasi oleh masa pakai
vector
itu sendiri, yang di sini berbasis tumpukan, jadi tidak ada bedanya bagaimana penerapannya - kita hanya bisa memperlakukannya sebagai objek berbasis tumpukan dengan nilai semantik.Tidak begitu. Misalkan fungsinya adalah:
Jadi, apa pun yang memiliki
swap
fungsi (dan jenis nilai kompleks apa pun harus memilikinya) dapat berfungsi sebagai referensi rebindable ke beberapa data heap, di bawah sistem yang menjamin satu pemilik data tersebut.Oleh karena itu, pendekatan C ++ modern adalah tidak pernah menyimpan alamat data heap dalam variabel pointer lokal polos. Semua alokasi heap harus disembunyikan di dalam kelas.
Jika Anda melakukannya, Anda dapat menganggap semua variabel dalam program Anda seolah-olah mereka adalah tipe nilai sederhana, dan melupakan heap sama sekali (kecuali saat menulis kelas pembungkus seperti nilai baru untuk beberapa data heap, yang seharusnya tidak biasa) .
Anda hanya perlu menyimpan satu pengetahuan khusus untuk membantu Anda mengoptimalkan: jika memungkinkan, alih-alih menugaskan satu variabel ke variabel lain seperti ini:
tukar mereka seperti ini:
karena jauh lebih cepat dan tidak ada pengecualian. Satu-satunya persyaratan adalah Anda tidak perlu
b
terus memegang nilai yang sama (ini akan mendapatkana
nilai, yang akan dibuanga = b
).Sisi negatifnya adalah pendekatan ini memaksa Anda untuk mengembalikan nilai dari fungsi melalui parameter keluaran, bukan nilai pengembalian yang sebenarnya. Tapi mereka memperbaikinya di C ++ 0x dengan referensi rvalue .
Dalam situasi yang paling rumit dari semuanya, Anda akan membawa ide ini ke ekstrem umum dan menggunakan kelas penunjuk cerdas seperti
shared_ptr
yang sudah ada di tr1. (Meskipun saya berpendapat bahwa jika Anda tampaknya membutuhkannya, Anda mungkin telah pindah ke luar sweet spot penerapan Standar C ++.)sumber
Anda juga akan menyimpan item di heap jika perlu digunakan di luar lingkup fungsi yang membuatnya. Satu idiom yang digunakan dengan objek tumpukan disebut RAII - ini melibatkan penggunaan objek berbasis tumpukan sebagai pembungkus untuk sumber daya, ketika objek dimusnahkan, sumber daya akan dibersihkan. Objek berbasis tumpukan lebih mudah untuk dilacak saat Anda mungkin melempar pengecualian - Anda tidak perlu mengkhawatirkan diri Anda sendiri dengan menghapus objek berbasis tumpukan di penangan pengecualian. Inilah sebabnya mengapa pointer mentah biasanya tidak digunakan dalam C ++ modern, Anda akan menggunakan pointer pintar yang bisa menjadi pembungkus berbasis tumpukan untuk pointer mentah ke objek berbasis heap.
sumber
Untuk menambah jawaban lain, bisa juga tentang kinerja, setidaknya sedikit. Bukan berarti Anda harus mengkhawatirkan hal ini kecuali relevan untuk Anda, tetapi:
Mengalokasikan di heap membutuhkan pelacakan blok memori, yang bukan operasi waktu-konstan (dan memerlukan beberapa siklus dan overhead). Ini bisa menjadi lebih lambat karena memori menjadi terfragmentasi, dan / atau Anda hampir menggunakan 100% ruang alamat Anda. Di sisi lain, alokasi tumpukan adalah operasi waktu-konstan, pada dasarnya "bebas".
Hal lain yang perlu dipertimbangkan (sekali lagi, sangat penting hanya jika itu menjadi masalah) adalah biasanya ukuran tumpukan diperbaiki, dan bisa jauh lebih rendah daripada ukuran tumpukan. Jadi jika Anda mengalokasikan objek besar atau banyak objek kecil, Anda mungkin ingin menggunakan heap; jika Anda kehabisan ruang tumpukan, runtime akan menampilkan pengecualian tituler situs. Biasanya bukan masalah besar, tetapi hal lain yang perlu dipertimbangkan.
sumber
Stack lebih efisien, dan data cakupan yang lebih mudah dikelola.
Tetapi heap harus digunakan untuk apa pun yang lebih besar dari beberapa KB (mudah di C ++, cukup buat
boost::scoped_ptr
di tumpukan untuk menahan penunjuk ke memori yang dialokasikan).Pertimbangkan algoritma rekursif yang terus memanggil dirinya sendiri. Sangat sulit untuk membatasi dan atau menebak total penggunaan tumpukan! Sedangkan di heap, pengalokasi (
malloc()
ataunew
) dapat menunjukkan kehabisan memori dengan mengembalikanNULL
atauthrow
ing.Sumber : Kernel Linux yang tumpukannya tidak lebih dari 8KB!
sumber
std::unique_ptr
, yang seharusnya lebih disukai daripada pustaka eksternal seperti Boost (meskipun hal itu memenuhi standar dari waktu ke waktu).Untuk kelengkapannya, Anda dapat membaca artikel Miro Samek tentang masalah penggunaan heap dalam konteks perangkat lunak yang disematkan .
Tumpukan Masalah
sumber
Pilihan apakah akan mengalokasikan di heap atau di stack adalah salah satu pilihan yang dibuat untuk Anda, bergantung pada bagaimana variabel Anda dialokasikan. Jika Anda mengalokasikan sesuatu secara dinamis, menggunakan panggilan "baru", Anda mengalokasikan dari heap. Jika Anda mengalokasikan sesuatu sebagai variabel global, atau sebagai parameter dalam fungsi, itu dialokasikan di stack.
sumber
Menurut saya ada dua faktor penentu
Saya lebih suka menggunakan stack dalam banyak kasus, tetapi jika Anda memerlukan akses ke variabel di luar cakupan, Anda dapat menggunakan heap.
Untuk meningkatkan kinerja saat menggunakan heap, Anda juga dapat menggunakan fungsionalitas tersebut untuk membuat blok heap dan yang dapat membantu dalam mendapatkan kinerja daripada mengalokasikan setiap variabel di lokasi memori yang berbeda.
sumber
mungkin ini telah dijawab dengan cukup baik. Saya ingin mengarahkan Anda ke rangkaian artikel di bawah ini untuk memiliki pemahaman yang lebih dalam tentang detail tingkat rendah. Alex Darby memiliki serangkaian artikel, di mana dia memandu Anda dengan debugger. Ini Bagian 3 tentang Stack. http://www.altdevblogaday.com/2011/12/14/cc-low-level-curriculum-part-3-the-stack/
sumber