Saya biasanya tidak punya masalah memutuskan apakah beberapa data harus bersifat global, statis atau di stack (Tidak ada alokasi dinamis di sini, jadi tidak ada gunanya tumpukan). Saya juga telah membaca beberapa T / A seperti ini tetapi pertanyaan saya lebih spesifik karena melibatkan sejumlah besar data, sangat besar dibandingkan dengan memori sistem.
Saya sedang mengerjakan kode yang sudah ada yang saya coba tingkatkan (desain, kemungkinan masalah, kinerja, dll.). Kode ini berjalan pada MCU 8bit lama dengan hanya 4KB RAM . Dalam kode ini saya menghadapi penggunaan array hampir 1KB (ya, 1KB pada sistem RAM 4KB ). Setiap byte array ini digunakan, bukan itu pertanyaannya. Masalahnya adalah array ini adalah array statis dalam file yang dideklarasikan, sehingga siklus hidupnya sama dengan program (yaitu dapat dianggap tak terbatas).
Namun, setelah membaca kode, saya baru tahu bahwa array ini tidak memerlukan siklus hidup yang tak terbatas, itu dibangun dan ditangani dengan cara yang sepenuhnya prosedural, jadi kita harus dapat mendeklarasikannya hanya dalam fungsi di mana ia digunakan, dengan cara ini akan berada di stack, dan karena itu kami akan menghemat 1KB RAM ini.
Sekarang pertanyaannya: Apakah ini ide yang bagus? Dari sudut pandang desain, jika tidak memerlukan siklus hidup tak terbatas / global, itu milik stack. Tapi hei, itu 1KB dari 4KB, tidak ada kekurangan mengalokasikan 25% dari RAM seperti ini? (itu mungkin 50% atau lebih dari tumpukan)
Bisakah seseorang berbagi pengalaman dengan situasi seperti ini, atau apakah seseorang memikirkan alasan yang sah untuk tidak meletakkan array ini di stack? Saya mencari kelemahan teknis serta komentar pada desain.
Satu-satunya hal yang saya sadari adalah saya harus memastikan bahwa saya benar-benar memiliki 1KB stack gratis ketika memasuki fungsi ini. Mungkin hanya itu yang harus saya selesaikan, mungkin tidak.
Jawaban:
Ya, dan itu adalah kendala yang kuat. Anda akan lebih yakin secara statis daripada memiliki ruang besar di stack. Jika kode ini kecil, jika Anda menggunakan GCC terbaru untuk mengkompilasi kode Anda, lihat ini .
BTW, beberapa mikroprosesor murah mungkin menggunakan bingkai panggilan "besar" lebih mahal daripada yang "normal" (misalnya karena set instruksi mereka akan memilih offset satu byte dari penunjuk tumpukan). YMMV.
Juga, jika Anda melakukan pengkodean dalam C dan jika Anda merasa bahwa array besar Anda dapat digunakan kembali untuk tujuan lain, Anda dapat mempertimbangkan untuk menjadikannya anggota serikat pekerja (dengan tipe variabel global
union
). Ya, itu sangat jelek.Atau, Anda dapat mempertimbangkan pengkodean beberapa pengalokasian tumpukan primitif yang cocok untuk aplikasi Anda (dan itu bisa memiliki API yang berbeda dengan
malloc
&free
....).sumber
gcc -flto -Os
? ) dan Anda mungkin mendapatkan beberapa memori ....Orang-orang cenderung berhati-hati dengan tumpukan besar, karena itu tumbuh mundur dalam RAM dan menimpa nilai-nilai variabel, yang mengarah ke perilaku yang tidak dapat dijelaskan. Itu menjadi lebih buruk, karena Anda perlu mengetahui alamat penunjuk tumpukan serendah mungkin dan kurangi ukuran yang dialokasikan ketika memasuki rutinitas.
Ini semua adalah pekerjaan untuk manajemen memori perangkat keras (harus menghasilkan jebakan atau kesalahan ketika stack overflow) atau untuk kompiler, mengingat ia memiliki fitur untuk jenis analisis ini.
Jika tidak, Anda dapat melakukan apa yang Anda inginkan dengan RAM Anda.
sumber
Seperti jawaban sebelumnya telah menunjukkan, saya juga akan merekomendasikan meninggalkan array statis jika cocok dengan memori. Dalam kebanyakan kasus, jauh lebih penting untuk memiliki jejak memori deterministik, bahkan jika itu berarti Anda "membuang" memori untuk variabel yang tidak digunakan sepanjang waktu. Menempatkan array besar ke tumpukan Anda akan terlalu mudah meledakkannya, dan tumpukan berlebihan cenderung menyebabkan masalah yang sulit ditemukan dan sulit direproduksi (jika Anda tidak dapat menggunakan MMU untuk melindungi tumpukan).
Saran untuk berbagi blok dengan beberapa data lain dengan serikat adalah IMO valid, meskipun itu juga bisa menjadi sumber untuk masalah yang sulit ditemukan, jika Anda menemukan variabel yang salah di dalamnya.
Jika Anda kehabisan memori dan sangat perlu membuat variabel yang lebih pendek untuk membagikannya, sebelum memindahkan array ke stack, saya akan mempertimbangkan untuk menambah alokasi memori dinamis, meskipun ia memiliki kekurangannya sendiri. Dalam hal ini mungkin bukan jawaban, karena array terdengar cukup besar dibandingkan dengan memori yang tersedia.
sumber
Anda memiliki satu opsi lain jika Anda memiliki semacam penyimpanan flash. Anda dapat menukar kecepatan akses ram dengan menyimpan data Anda dalam sekejap dan membaca & mencari di sana. Anda hanya perlu memuat satu catatan sekaligus ke dalam ram. Akan sedikit lebih rumit jika Anda harus dapat memperbarui catatan. Anda akan membutuhkan mekanisme level-pakai yang tersegmentasi. Saya telah melakukan ini di masa lalu dan memasukkan indeks untuk mempercepat akses.
sumber
Terutama ketika bekerja dengan sistem embedded, Anda ingin sebanyak mungkin kegagalan terjadi pada waktu kompilasi dan tidak ada yang gagal pada waktu berjalan (bagus jika kita bisa mencapai ini, meskipun ...).
Membuat array besar yang mungkin Anda butuhkan dalam keadaan arbitrer dari program Anda yang dialokasikan secara statis melakukan hal itu - Linker akhirnya akan memperingatkan Anda "ini tidak cocok dengan RAM", sedangkan alokasi tumpukan hanya akan membuat program Anda macet dengan tumpukan yang sulit di-debug meluap.
sumber