Pertanyaan Apa dan di mana tumpukan dan tumpukannya?


Pemrograman buku bahasa menjelaskan bahwa jenis nilai dibuat pada tumpukan, dan tipe referensi dibuat pada tumpukan, tanpa menjelaskan apa dua hal ini. Saya belum membaca penjelasan yang jelas tentang ini. Saya mengerti apa setumpuk aku s. Tapi,

  • di mana dan apa yang mereka (secara fisik dalam memori komputer nyata)?
  • Sejauh mana mereka dikendalikan oleh OS atau bahasa runtime?
  • Apa ruang lingkup mereka?
  • Apa yang menentukan ukuran masing-masing?
  • Apa yang membuat lebih cepat?

7116
2017-09-17 04:18


asal


Jawaban:


Tumpukannya adalah memori yang disisihkan sebagai ruang gores untuk benang eksekusi. Ketika sebuah fungsi dipanggil, sebuah blok dicadangkan di bagian atas tumpukan untuk variabel lokal dan beberapa data pembukuan. Ketika fungsi itu kembali, blok tersebut menjadi tidak terpakai dan dapat digunakan saat berikutnya suatu fungsi dipanggil. Tumpukan selalu disediakan dalam urutan LIFO (terakhir di luar pertama); blok yang terakhir dicadangkan selalu blok berikutnya yang dibebaskan. Ini membuatnya sangat mudah untuk melacak tumpukan; membebaskan blok dari tumpukan tidak lebih dari menyesuaikan satu penunjuk.

Tumpukan adalah memori yang disisihkan untuk alokasi dinamis. Berbeda dengan tumpukan, tidak ada pola yang dipaksakan untuk alokasi dan dealokasi blok dari heap; Anda dapat mengalokasikan blok setiap saat dan membebaskannya kapan saja. Ini membuatnya jauh lebih rumit untuk melacak bagian mana dari tumpukan yang dialokasikan atau gratis pada waktu tertentu; ada banyak alokasi tumpukan tersedia untuk menyesuaikan kinerja tumpukan untuk pola penggunaan yang berbeda.

Setiap thread mendapat setumpuk, sementara biasanya hanya ada satu tumpukan untuk aplikasi (meskipun tidak jarang memiliki banyak tumpukan untuk berbagai jenis alokasi).

Untuk menjawab pertanyaan Anda secara langsung:

Sejauh mana mereka dikendalikan oleh OS atau bahasa runtime?

OS mengalokasikan stack untuk setiap thread level sistem ketika thread dibuat. Biasanya OS dipanggil oleh runtime bahasa untuk mengalokasikan heap untuk aplikasi.

Apa ruang lingkup mereka?

Tumpukan dilampirkan ke utas, jadi ketika utas keluar tumpukan ditaklukkan kembali. Heap biasanya dialokasikan pada startup aplikasi oleh runtime, dan direklamasi ketika aplikasi (proses teknis) keluar.

Apa yang menentukan ukuran masing-masing? 

Ukuran tumpukan ditetapkan saat utas dibuat. Ukuran heap diatur pada startup aplikasi, tetapi dapat bertambah karena diperlukan ruang (pengalokasi meminta lebih banyak memori dari sistem operasi).

Apa yang membuat lebih cepat?

Tumpukan lebih cepat karena pola akses membuatnya sepele untuk mengalokasikan dan mengalihkan memori dari itu (pointer / integer hanya bertambah atau dikurangi), sedangkan tumpukan memiliki pembukuan yang jauh lebih kompleks yang terlibat dalam alokasi atau dealokasi. Juga, setiap byte dalam stack cenderung digunakan kembali sangat sering yang berarti cenderung dipetakan ke cache prosesor, membuatnya sangat cepat. Pencapaian kinerja lain untuk heap adalah bahwa tumpukan, yang sebagian besar merupakan sumber daya global, biasanya harus aman multi-threading, yaitu setiap alokasi dan dealokasi perlu - biasanya - disinkronkan dengan "semua" akses heap lainnya dalam program.

Demonstrasi yang jelas:
Sumber gambar: vikashazrati.wordpress.com


5228
2017-09-17 04:52



Tumpukan:

  • Disimpan dalam RAM komputer seperti tumpukan.
  • Variabel yang dibuat pada stack akan keluar dari ruang lingkup dan secara otomatis dialokasi.
  • Jauh lebih cepat mengalokasikan dibandingkan dengan variabel di heap.
  • Diimplementasikan dengan struktur data tumpukan yang sebenarnya.
  • Menyimpan data lokal, alamat pengirim, yang digunakan untuk pengiriman parameter.
  • Dapat memiliki tumpukan overflow ketika terlalu banyak tumpukan yang digunakan (sebagian besar dari rekursi yang tak terbatas atau terlalu dalam, alokasi sangat besar).
  • Data yang dibuat di stack dapat digunakan tanpa pointer.
  • Anda akan menggunakan stack jika Anda tahu persis berapa banyak data yang perlu Anda alokasikan sebelum waktu kompilasi dan itu tidak terlalu besar.
  • Biasanya memiliki ukuran maksimum yang sudah ditentukan saat program Anda dimulai.

Tumpukan:

  • Disimpan dalam RAM komputer seperti tumpukan.
  • Dalam C ++, variabel pada heap harus dihancurkan secara manual dan tidak pernah keluar dari ruang lingkup. Data dibebaskan dengan delete, delete[], atau free.
  • Lebih lambat untuk mengalokasikan dibandingkan dengan variabel pada stack.
  • Digunakan atas permintaan untuk mengalokasikan satu blok data untuk digunakan oleh program.
  • Dapat memiliki fragmentasi ketika ada banyak alokasi dan de-alokasi.
  • Dalam C ++ atau C, data yang dibuat di heap akan diarahkan oleh pointer dan dialokasikan dengan new atau malloc masing-masing.
  • Dapat memiliki kegagalan alokasi jika terlalu besar buffer diminta untuk dialokasikan.
  • Anda akan menggunakan heap jika Anda tidak tahu persis berapa banyak data yang Anda perlukan pada waktu berjalan atau jika Anda perlu mengalokasikan banyak data.
  • Bertanggung jawab atas kebocoran memori.

Contoh:

int foo()
{
  char *pBuffer; //<--nothing allocated yet (excluding the pointer itself, which is allocated here on the stack).
  bool b = true; // Allocated on the stack.
  if(b)
  {
    //Create 500 bytes on the stack
    char buffer[500];

    //Create 500 bytes on the heap
    pBuffer = new char[500];

   }//<-- buffer is deallocated here, pBuffer is not
}//<--- oops there's a memory leak, I should have called delete[] pBuffer;

2092
2017-09-17 04:20



Hal yang paling penting adalah tumpukan dan tumpukan adalah istilah umum untuk cara-cara di mana memori dapat dialokasikan. Mereka dapat diimplementasikan dengan berbagai cara, dan ketentuan berlaku untuk konsep dasar.

  • Dalam tumpukan item, item diletakkan satu di atas yang lain dalam urutan yang ditempatkan di sana, dan Anda hanya dapat menghapus yang teratas (tanpa menjatuhkan semuanya ke atas).

    Stack like a stack of papers

    Kesederhanaan tumpukan adalah bahwa Anda tidak perlu memelihara tabel yang berisi catatan setiap bagian dari memori yang dialokasikan; satu-satunya informasi keadaan yang Anda butuhkan adalah penunjuk tunggal ke ujung tumpukan. Untuk mengalokasikan dan mendelegasikan, Anda hanya menambah dan mengurangi penunjuk tunggal itu. Catatan: tumpukan terkadang dapat diimplementasikan untuk memulai di bagian atas bagian memori dan memperluas ke bawah daripada tumbuh ke atas.

  • Dalam tumpukan, tidak ada urutan khusus untuk cara penempatan item. Anda dapat meraih dan menghapus item dalam urutan apa pun karena tidak ada item 'teratas' yang jelas.

    Heap like a heap of licorice allsorts

    Alokasi heap membutuhkan pemeliharaan catatan lengkap dari apa yang dialokasikan memori dan apa yang tidak, serta beberapa pemeliharaan overhead untuk mengurangi fragmentasi, menemukan segmen memori yang berdekatan cukup besar untuk menyesuaikan dengan ukuran yang diminta, dan seterusnya. Memori dapat dinonaktifkan setiap saat meninggalkan ruang kosong. Kadang-kadang pengalokasi memori akan melakukan tugas-tugas pemeliharaan seperti defragmenting memori dengan memindahkan memori yang dialokasikan di sekitar, atau mengumpulkan sampah - mengidentifikasi pada saat runtime ketika memori tidak lagi dalam lingkup dan deallocating itu.

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 OS atau bahasa runtime?

    Seperti disebutkan, tumpukan dan tumpukan adalah istilah umum, dan dapat diimplementasikan dalam banyak cara. Program komputer biasanya memiliki tumpukan yang disebut a sebut tumpukan yang menyimpan informasi yang relevan dengan fungsi saat ini seperti penunjuk ke fungsi mana yang dipanggil, dan setiap variabel lokal. Karena fungsi memanggil fungsi lain dan kemudian kembali, tumpukan menumpuk dan menyusut untuk menahan informasi dari fungsi lebih jauh ke bawah 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 memori apa pun yang dialokasikan secara dinamis dan acak; iya tidak berurutan. Memori biasanya dialokasikan oleh OS, dengan aplikasi memanggil fungsi API untuk melakukan alokasi ini. Ada sedikit biaya yang diperlukan untuk mengelola memori yang dialokasikan secara dinamis, yang biasanya ditangani oleh OS.

  • Apa ruang lingkup mereka?

    Panggilan stack adalah suatu konsep tingkat rendah yang tidak berhubungan dengan 'ruang lingkup' dalam pengertian pemrograman. Jika Anda membongkar beberapa kode, Anda akan melihat referensi gaya penunjuk relatif ke bagian-bagian tumpukan, tetapi sejauh bahasa tingkat yang lebih tinggi yang bersangkutan, bahasa membebankan aturan lingkup sendiri. Satu aspek penting dari tumpukan, bagaimanapun, adalah bahwa sekali fungsi kembali, semua yang lokal ke fungsi itu segera dibebaskan dari tumpukan. Itu berfungsi seperti yang Anda harapkan untuk bekerja mengingat bagaimana bahasa pemrograman Anda bekerja. Dalam tumpukan, itu juga sulit untuk didefinisikan. Ruang lingkup adalah apa pun yang diekspos oleh OS, tetapi bahasa pemrograman Anda mungkin menambahkan aturannya tentang apa yang "ruang lingkup" dalam aplikasi Anda. Arsitektur prosesor dan OS menggunakan pengalamatan virtual, yang diterjemahkan prosesor ke alamat fisik dan ada kesalahan halaman, dll. Mereka melacak halaman apa yang menjadi bagian dari aplikasi mana. Anda tidak perlu khawatir tentang hal 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 (lebih lanjut tentang itu di paragraf terakhir). Compiler bahasa atau OS menentukan ukurannya. Anda tidak menyimpan data dalam jumlah besar di stack, jadi itu akan cukup besar sehingga tidak boleh digunakan sepenuhnya, kecuali dalam kasus rekursi tanpa akhir yang tidak diinginkan (karenanya, "stack overflow") atau keputusan pemrograman yang tidak biasa lainnya.

    Heap adalah istilah umum untuk segala sesuatu yang dapat dialokasikan secara dinamis. Tergantung pada cara mana Anda melihatnya, itu terus berubah ukuran. Dalam prosesor modern dan sistem operasi, cara yang tepat kerjanya sangat abstrak, jadi Anda biasanya tidak perlu khawatir tentang cara kerjanya jauh ke 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 lebih cepat?

    Tumpukan lebih cepat karena semua memori bebas selalu berdekatan. 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 secara khusus, cepat daftar untuk tujuan ini. Terlebih lagi, operasi berikutnya pada tumpukan biasanya terkonsentrasi di daerah-daerah memori yang sangat dekat, yang pada tingkat yang sangat rendah baik untuk optimasi oleh prosesor di-mati cache.


1259
2018-03-19 14:38



(Saya telah memindahkan jawaban ini dari pertanyaan lain yang kurang lebih merupakan penipuan dari yang satu ini.)

Jawaban atas pertanyaan Anda adalah implementasi spesifik dan dapat bervariasi di seluruh compiler dan arsitektur prosesor. Namun, inilah penjelasan yang disederhanakan.

  • Tumpukan dan tumpukan adalah area memori yang dialokasikan dari sistem operasi yang mendasarinya (seringkali memori virtual yang dipetakan ke memori fisik sesuai permintaan).
  • Dalam lingkungan multi-threaded setiap utas akan memiliki tumpukan independennya sendiri tetapi mereka akan berbagi heap. Akses bersamaan harus dikontrol pada heap dan tidak mungkin di stack.

Heap

  • Tumpukan berisi daftar terkait dari blok yang digunakan dan gratis. Alokasi baru di heap (oleh new atau malloc) dipenuhi dengan membuat blok yang sesuai dari salah satu blok gratis. Ini membutuhkan pembaruan daftar blok di heap. Ini informasi meta tentang blok di heap juga disimpan di heap sering di area kecil hanya di depan setiap blok.
  • Ketika tumpukan itu tumbuh blok baru sering dialokasikan dari alamat yang lebih rendah ke alamat yang lebih tinggi. Dengan demikian Anda dapat menganggap heap sebagai a tumpukan blok memori yang tumbuh dalam ukuran sebagai memori dialokasikan. Jika tumpukan terlalu kecil untuk alokasi ukuran sering dapat ditingkatkan dengan memperoleh lebih banyak memori dari sistem operasi yang mendasarinya.
  • Pengalokasian dan pengalihan banyak blok kecil dapat meninggalkan tumpukan dalam keadaan di mana ada banyak blok kecil kecil yang diselingi antara blok yang digunakan. Permintaan untuk mengalokasikan blok besar mungkin gagal karena tidak ada blok gratis yang cukup besar untuk memenuhi permintaan alokasi meskipun ukuran gabungan blok bebas mungkin cukup besar. Ini disebut fragmentasi tumpukan.
  • Ketika sebuah blok yang digunakan yang berdekatan dengan blok bebas adalah deallocated blok bebas baru dapat digabung dengan blok bebas yang berdekatan untuk membuat blok bebas yang lebih besar secara efektif mengurangi fragmentasi tumpukan.

The heap

Tumpukan

  • Tumpukan sering bekerja berdekatan dengan register khusus pada CPU bernama penunjuk tumpukan. Awalnya penunjuk tumpukan menunjuk ke bagian atas tumpukan (alamat tertinggi pada tumpukan).
  • CPU memiliki instruksi khusus untuk mendorong nilai ke stack dan muncul mereka kembali dari tumpukan. Setiap Dorong menyimpan nilai pada lokasi saat ini dari penunjuk tumpukan dan mengurangi penunjuk tumpukan. SEBUAH pop mengambil nilai yang ditunjukkan oleh penunjuk tumpukan dan kemudian meningkatkan penunjuk tumpukan (jangan bingung dengan fakta itu menambahkan nilai ke tumpukan menurun penunjuk tumpukan dan menghapus sebuah nilai meningkat saya t. Ingat tumpukan itu tumbuh ke bawah). Nilai-nilai yang disimpan dan diambil adalah nilai-nilai register CPU.
  • Ketika suatu fungsi disebut CPU menggunakan instruksi khusus yang mendorong arus penunjuk instruksi, yaitu alamat kode yang dieksekusi di tumpukan. CPU kemudian melompat ke fungsi dengan mengatur penunjuk instruksi ke alamat fungsi yang dipanggil. Kemudian, ketika fungsi kembali, pointer instruksi lama muncul dari stack dan eksekusi dilanjutkan pada kode tepat setelah panggilan ke fungsi.
  • Ketika suatu fungsi dimasukkan, penunjuk tumpukan diturunkan untuk mengalokasikan lebih banyak ruang pada tumpukan untuk variabel lokal (otomatis). Jika fungsi memiliki satu variabel lokal 32 bit, empat byte disisihkan di stack. Ketika fungsi kembali, penunjuk tumpukan dipindahkan kembali untuk membebaskan area yang dialokasikan.
  • Jika suatu fungsi memiliki parameter, ini didorong ke stack sebelum panggilan ke fungsi. Kode dalam fungsi kemudian dapat menavigasi tumpukan dari penunjuk tumpukan saat ini untuk menemukan nilai-nilai ini.
  • Panggilan fungsi bersarang berfungsi seperti jimat. Setiap panggilan baru akan mengalokasikan parameter fungsi, alamat pengirim dan ruang untuk variabel lokal dan ini catatan aktivasi dapat ditumpuk untuk panggilan bertingkat dan akan bersantai dengan cara yang benar ketika fungsi kembali.
  • Karena tumpukan adalah blok memori yang terbatas, Anda dapat menyebabkan tumpah melimpah dengan memanggil terlalu banyak fungsi bertingkat dan / atau mengalokasikan terlalu banyak ruang untuk variabel lokal. Seringkali area memori yang digunakan untuk tumpukan diatur sedemikian rupa sehingga menulis di bawah bagian bawah (alamat terendah) dari tumpukan akan memicu jebakan atau pengecualian dalam CPU. Kondisi luar biasa ini kemudian dapat ditangkap oleh runtime dan diubah menjadi semacam pengecualian overflow stack.

The stack

Dapatkah suatu fungsi dialokasikan pada heap alih-alih 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 bertingkat.

Bagaimana tumpukan dikelola benar-benar sesuai dengan lingkungan runtime. C menggunakan malloc dan C ++ digunakan new, tetapi banyak bahasa lain memiliki koleksi sampah.

Namun, tumpukan adalah fitur yang lebih rendah tingkat terkait erat dengan arsitektur prosesor. Menumbuhkan tumpukan ketika tidak ada cukup ruang tidak terlalu sulit karena dapat diimplementasikan dalam panggilan perpustakaan yang menangani heap. Namun, menumpuk tumpukan seringkali tidak mungkin karena tumpukan tumpahan hanya ditemukan ketika sudah terlambat; dan mematikan benang eksekusi adalah satu-satunya pilihan yang layak.


663
2017-07-31 15:54



Dalam kode C # berikut

public void Method1()
{
    int i = 4;
    int y = 2;
    class1 cls1 = new class1();
}

Beginilah cara memori dikelola

Picture of variables on the stack

Local Variables yang hanya perlu berlangsung selama pemanggilan fungsi masuk dalam tumpukan. Tumpukan digunakan untuk variabel yang seumur hidup kita tidak benar-benar tahu di depan tetapi kita mengharapkan mereka untuk bertahan sementara. Dalam kebanyakan bahasa, sangat penting bahwa kita tahu pada waktu kompilasi seberapa besar variabel adalah jika kita ingin menyimpannya di stack.

Objek (yang bervariasi dalam ukuran saat kami memperbaruinya) pergi ke heap karena kami tidak tahu pada waktu pembuatan berapa lama mereka akan bertahan. Dalam banyak bahasa, tumpukan sampah dikumpulkan untuk menemukan objek (seperti objek cls1) yang tidak lagi memiliki referensi.

Di Java, sebagian besar objek langsung masuk ke heap. Dalam bahasa seperti C / C ++, struct dan kelas sering dapat tetap berada di stack ketika Anda tidak berurusan dengan pointer.

Informasi lebih lanjut dapat ditemukan di sini:

Perbedaan antara tumpukan dan tumpukan alokasi memori «timmurphy.org

dan di sini:

Membuat Objek di Tumpukan dan Tumpukan

Artikel ini adalah sumber gambar di atas: Enam konsep .NET penting: Stack, heap, jenis nilai, tipe referensi, tinju, dan unboxing - CodeProject

tetapi sadari mungkin mengandung beberapa ketidakakuratan.


350
2017-11-09 12:28



Tumpukan Ketika Anda memanggil suatu fungsi, argumen ke fungsi itu ditambah beberapa overhead lainnya diletakkan di stack. Beberapa info (seperti tempat untuk kembali) juga disimpan di sana. Ketika Anda mendeklarasikan variabel di dalam fungsi Anda, variabel itu juga dialokasikan pada stack.

Deallocating stack cukup sederhana karena Anda selalu membatalkan dalam urutan terbalik di mana Anda mengalokasikan. Stack stuff ditambahkan saat Anda memasukkan fungsi, data terkait dihapus saat Anda keluar. Ini berarti bahwa Anda cenderung tinggal di dalam wilayah kecil tumpukan kecuali Anda memanggil banyak fungsi yang memanggil banyak fungsi lain (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 luar angkasa yang akan dibuat oleh program Anda, kemungkinan Anda akan menggunakan operator baru (atau malloc atau yang setara) untuk membuat setiap pesawat ruang angkasa. Alokasi ini akan bertahan untuk sementara waktu, jadi sepertinya kami akan membebaskan barang-barang dalam urutan yang berbeda dari yang kami ciptakan.

Dengan demikian, heap jauh lebih kompleks, karena akhirnya ada daerah-daerah memori yang tidak terpakai disisipkan dengan potongan-potongan yang - memori akan terpecah-pecah. Menemukan memori gratis dari ukuran yang Anda butuhkan adalah masalah yang sulit. Inilah sebabnya mengapa tumpukan harus dihindari (meskipun masih sering digunakan).

Pelaksanaan Penerapan tumpukan dan tumpukan biasanya turun ke runtime / OS. Seringkali permainan dan aplikasi lain yang kinerja penting membuat solusi memori mereka sendiri yang mengambil sebagian besar memori dari heap dan kemudian menaruhnya secara internal untuk menghindari mengandalkan OS untuk memori.

Ini hanya praktis jika penggunaan memori Anda sangat berbeda dari norma - yaitu untuk permainan di mana Anda memuat tingkat dalam satu operasi besar dan dapat membuang seluruh jauh dalam operasi besar lainnya.

Lokasi fisik dalam memori Ini kurang relevan dari yang Anda kira 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 pada hard disk!). Alamat yang Anda dapatkan untuk tumpukan berada dalam urutan yang meningkat saat pohon panggilan Anda semakin dalam. Alamat untuk heap tidak bisa diprediksi (yaitu spesifikasi pujian) dan sejujurnya tidak penting.


190
2017-09-17 04:27



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 tumpukan, tumpukan, dan segmen data di bawah ini. Saya juga akan menunjukkan beberapa contoh di C / C + + dan Python untuk membantu orang mengerti.

"Statis" (AKA dialokasikan secara statis) variabel tidak dialokasikan pada stack. Jangan berasumsi begitu - banyak orang hanya karena "statis" terdengar sangat mirip "tumpukan". Mereka sebenarnya tidak ada di tumpukan maupun tumpukan. Ini adalah bagian dari apa yang disebut segmen data.

Namun, umumnya lebih baik untuk mempertimbangkan "cakupan"dan"seumur hidup"Bukan" stack "dan" heap ".

Cakupan mengacu pada bagian kode apa yang dapat mengakses variabel. Umumnya kita memikirkan lingkup lokal (hanya dapat diakses oleh fungsi saat ini) versus ruang lingkup global (dapat diakses di mana saja) meskipun cakupannya bisa menjadi jauh lebih kompleks.

Seumur hidup mengacu pada kapan suatu variabel dialokasikan dan dialihkan selama pelaksanaan program. Biasanya kita berpikir alokasi statis (variabel akan bertahan sepanjang durasi program, membuatnya berguna untuk menyimpan informasi yang sama di beberapa panggilan fungsi) versus alokasi otomatis (variabel hanya berlangsung selama satu panggilan ke fungsi, sehingga berguna untuk menyimpan informasi yang hanya digunakan selama fungsi Anda dan dapat dibuang begitu selesai) dibandingkan alokasi dinamis (variabel yang durasinya ditentukan saat runtime, daripada waktu kompilasi seperti statis atau otomatis).

Meskipun sebagian besar kompiler dan interpreter menerapkan perilaku ini sama dalam hal menggunakan tumpukan, tumpukan, dll, kompilator kadang-kadang dapat melanggar konvensi ini jika diinginkan selama perilaku benar. Misalnya, karena pengoptimalan, variabel lokal hanya dapat ada dalam daftar atau dihapus seluruhnya, meskipun sebagian besar variabel lokal ada dalam tumpukan. Seperti yang telah ditunjukkan dalam beberapa komentar, Anda bebas untuk mengimplementasikan kompilator yang bahkan tidak menggunakan tumpukan atau tumpukan, tetapi beberapa mekanisme penyimpanan lainnya (jarang dilakukan, karena tumpukan dan tumpukan sangat bagus untuk ini).

Saya akan memberikan beberapa kode C beranotasi sederhana untuk mengilustrasikan semua ini. Cara terbaik untuk belajar adalah dengan menjalankan program di bawah debugger dan melihat perilaku. Jika Anda lebih suka membaca python, lewati sampai akhir jawaban :)

// Statically allocated in the data segment when the program/DLL is first loaded
// Deallocated when the program/DLL exits
// scope - can be accessed from anywhere in the code
int someGlobalVariable;

// Statically allocated in the data segment when the program is first loaded
// Deallocated when the program/DLL exits
// scope - can be accessed from anywhere in this particular code file
static int someStaticVariable;

// "someArgument" is allocated on the stack each time MyFunction is called
// "someArgument" is deallocated when MyFunction returns
// scope - can be accessed only within MyFunction()
void MyFunction(int someArgument) {

    // Statically allocated in the data segment when the program is first loaded
    // Deallocated when the program/DLL exits
    // scope - can be accessed only within MyFunction()
    static int someLocalStaticVariable;

    // Allocated on the stack each time MyFunction is called
    // Deallocated when MyFunction returns
    // scope - can be accessed only within MyFunction()
    int someLocalVariable;

    // A *pointer* is allocated on the stack each time MyFunction is called
    // This pointer is deallocated when MyFunction returns
    // scope - the pointer can be accessed only within MyFunction()
    int* someDynamicVariable;

    // This line causes space for an integer to be allocated in the heap
    // when this line is executed. Note this is not at the beginning of
    // the call to MyFunction(), like the automatic variables
    // scope - only code within MyFunction() can access this space
    // *through this particular variable*.
    // However, if you pass the address somewhere else, that code
    // can access it too
    someDynamicVariable = new int;


    // This line deallocates the space for the integer in the heap.
    // If we did not write it, the memory would be "leaked".
    // Note a fundamental difference between the stack and heap
    // the heap must be managed. The stack is managed for us.
    delete someDynamicVariable;

    // In other cases, instead of deallocating this heap space you
    // might store the address somewhere more permanent to use later.
    // Some languages even take care of deallocation for you... but
    // always it needs to be taken care of at runtime by some mechanism.

    // When the function returns, someArgument, someLocalVariable
    // and the pointer someDynamicVariable are deallocated.
    // The space pointed to by someDynamicVariable was already
    // deallocated prior to returning.
    return;
}

// Note that someGlobalVariable, someStaticVariable and
// someLocalStaticVariable continue to exist, and are not
// deallocated until the program exits.

Contoh yang sangat menyolok tentang mengapa penting untuk membedakan antara masa pakai dan ruang lingkup adalah bahwa variabel dapat memiliki ruang lingkup lokal tetapi seumur hidup statis - misalnya, "someLocalStaticVariable" dalam contoh kode di atas. Variabel semacam itu dapat membuat kebiasaan penamaan umum tetapi tidak resmi sangat membingungkan. Misalnya ketika kita mengatakan "lokal"Kami biasanya bermaksud"Variabel lokal yang dialokasikan secara otomatis"dan ketika kita mengatakan global, biasanya kita berarti"Variabel global yang dialokasikan secara global". Sayangnya ketika datang ke hal-hal seperti"file yang mencakup variabel yang dialokasikan secara statis"banyak orang hanya mengatakan ..."Hah???".

Beberapa pilihan sintaksis dalam C / C + + memperparah masalah ini - misalnya banyak orang berpikir variabel global tidak "statis" karena sintaks yang ditunjukkan di bawah ini.

int var1; // Has global scope and static allocation
static int var2; // Has file scope and static allocation

int main() {return 0;}

Perhatikan bahwa menempatkan kata kunci "statis" dalam deklarasi di atas mencegah var2 memiliki cakupan global. Namun demikian, var1 global memiliki alokasi statis. Ini tidak intuitif! Untuk alasan ini, saya mencoba untuk tidak pernah menggunakan kata "statis" ketika menjelaskan ruang lingkup, dan sebagai gantinya mengatakan sesuatu seperti "file" atau "file terbatas" lingkup. Namun banyak orang menggunakan frase "statis" atau "lingkup statis" untuk menggambarkan suatu variabel yang hanya dapat diakses dari satu file kode. Dalam konteks seumur hidup, "statis" selalu berarti variabel dialokasikan pada saat program mulai dan dibatalkan saat program keluar.

Beberapa orang menganggap konsep-konsep ini sebagai C / C ++ spesifik. Mereka tidak. Sebagai contoh, contoh Python di bawah ini menggambarkan ketiga jenis alokasi (ada beberapa perbedaan halus yang mungkin dalam bahasa yang ditafsirkan yang tidak akan saya masuki di sini).

from datetime import datetime

class Animal:
    _FavoriteFood = 'Undefined' # _FavoriteFood is statically allocated

    def PetAnimal(self):
        curTime = datetime.time(datetime.now()) # curTime is automatically allocatedion
        print("Thank you for petting me. But it's " + str(curTime) + ", you should feed me. My favorite food is " + self._FavoriteFood)

class Cat(Animal):
    _FavoriteFood = 'tuna' # Note since we override, Cat class has its own statically allocated _FavoriteFood variable, different from Animal's

class Dog(Animal):
    _FavoriteFood = 'steak' # Likewise, the Dog class gets its own static variable. Important to note - this one static variable is shared among all instances of Dog, hence it is not dynamic!


if __name__ == "__main__":
    whiskers = Cat() # Dynamically allocated
    fido = Dog() # Dynamically allocated
    rinTinTin = Dog() # Dynamically allocated

    whiskers.PetAnimal()
    fido.PetAnimal()
    rinTinTin.PetAnimal()

    Dog._FavoriteFood = 'milkbones'
    whiskers.PetAnimal()
    fido.PetAnimal()
    rinTinTin.PetAnimal()

# Output is:
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is tuna
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is steak
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is steak
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is tuna
# Thank you for petting me. But it's 13:05:02.255000, you should feed me. My favorite food is milkbones
# Thank you for petting me. But it's 13:05:02.256000, you should feed me. My favorite food is milkbones

168
2017-09-17 04:48



Orang lain telah menjawab stroke yang luas dengan cukup baik, jadi saya akan memberikan beberapa rincian.

  1. Tumpukan dan tumpukan 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 tumpukannya sendiri. Anda juga dapat memiliki lebih dari satu tumpukan, misalnya beberapa konfigurasi DLL dapat menghasilkan alokasi DLL yang berbeda dari tumpukan yang berbeda, itulah mengapa biasanya ide yang buruk untuk melepaskan memori yang dialokasikan oleh pustaka yang berbeda.

  2. Dalam C Anda bisa mendapatkan manfaat dari alokasi panjang variabel melalui penggunaan alloca, yang mengalokasikan pada stack, sebagai lawan alokasi, yang mengalokasikan pada heap. Memori ini tidak akan bertahan dari pernyataan pengembalian Anda, tetapi ini berguna untuk buffer awal.

  3. Membuat buffer sementara besar pada Windows yang tidak Anda gunakan tidak gratis. Ini karena kompiler akan menghasilkan loop probe stack yang disebut setiap kali fungsi Anda dimasukkan untuk memastikan tumpukan ada (karena Windows menggunakan halaman penjaga tunggal di ujung tumpukan Anda untuk mendeteksi ketika perlu menumbuhkan tumpukan. Jika Anda mengakses memori lebih dari satu halaman dari ujung tumpukan, Anda akan crash). Contoh:

void myfunction()
{
   char big[10000000];
   // Do something that only uses for first 1K of big 99% of the time.
}

155
2017-09-17 07:16