Dalam pemrograman C, Anda dapat melewatkan pointer apa pun yang Anda suka sebagai argumen untuk dibebaskan, bagaimana ia mengetahui ukuran memori yang dialokasikan untuk dibebaskan? Setiap kali saya melewatkan pointer ke beberapa fungsi, saya juga harus melewati ukuran (yaitu array 10 elemen perlu menerima 10 sebagai parameter untuk mengetahui ukuran array), tetapi saya tidak harus meneruskan ukuran ke fungsi bebas. Mengapa tidak, dan bisakah saya menggunakan teknik yang sama ini dalam fungsi saya sendiri untuk menyelamatkan saya dari kebutuhan untuk menggerakkan variabel tambahan dari panjang array?
385
Jawaban:
Saat Anda menelepon
malloc()
, Anda menentukan jumlah memori yang akan dialokasikan. Jumlah memori yang sebenarnya digunakan sedikit lebih dari ini, dan termasuk informasi tambahan yang merekam (setidaknya) seberapa besar bloknya. Anda tidak dapat (andal) mengakses informasi lain itu - dan Anda juga tidak boleh :-).Ketika Anda menelepon
free()
, itu hanya melihat informasi tambahan untuk mengetahui seberapa besar blok itu.sumber
malloc_size()
andal mengakses ukuran blok darimalloc()
penunjuk ed. Tetapi tidak ada cara yang andal dan portabel.free()
mengharuskan programmer melaporkan secara akurat seberapa besarmalloc()
bloknya? Kebocoran memori sudah cukup buruk.malloc()
danfree()
, tetapi Anda harus menyimpan ukuran array? Mengapa mereka tidak memungkinkan untuk melakukan sesuatu sepertiblockSize(ptr)
jika mereka menyimpan informasi itu?Sebagian besar implementasi fungsi alokasi memori C akan menyimpan informasi akuntansi untuk setiap blok, baik in-line atau secara terpisah.
Salah satu cara khas (in-line) adalah untuk benar-benar mengalokasikan header dan memori yang Anda minta, diisi hingga beberapa ukuran minimum. Jadi misalnya, jika Anda meminta 20 byte, sistem dapat mengalokasikan blok 48 byte:
Alamat yang kemudian diberikan kepada Anda adalah alamat area data. Kemudian, ketika Anda membebaskan blok,
free
hanya akan mengambil alamat yang Anda berikan dan, dengan asumsi Anda belum memasukkan alamat itu atau memori di sekitarnya, periksa informasi akuntansi segera sebelum itu. Secara grafis, itu akan sepanjang garis:Perlu diingat ukuran header dan padding sepenuhnya implementasi didefinisikan (sebenarnya, semuanya didefinisikan implementasi (a) tetapi opsi akuntansi in-line adalah yang umum).
Checksum dan spidol khusus yang ada dalam informasi akuntansi sering menjadi penyebab kesalahan seperti "Memory Arena rusak" atau "Gratis ganda" jika Anda menimpa mereka atau membebaskan mereka dua kali.
Padding (untuk membuat alokasi lebih efisien) adalah mengapa Anda kadang-kadang dapat menulis sedikit di luar batas ruang yang Anda minta tanpa menimbulkan masalah (tetap saja, jangan lakukan itu, itu perilaku yang tidak ditentukan dan, hanya karena itu bekerja kadang-kadang, tidak t berarti tidak apa-apa untuk melakukannya).
(a) Saya sudah menulis implementasi
malloc
dalam sistem embedded di mana Anda mendapat 128 byte tidak peduli apa yang Anda minta (itu adalah ukuran struktur terbesar dalam sistem), dengan asumsi Anda meminta 128 byte atau kurang (permintaan untuk lebih banyak akan harus dipenuhi dengan nilai pengembalian NULL). Bit-mask yang sangat sederhana (yaitu, bukan in-line) digunakan untuk memutuskan apakah sepotong 128-byte dialokasikan atau tidak.Yang lain yang saya kembangkan memiliki kumpulan yang berbeda untuk potongan 16-byte, potongan 64-byte, potongan 256-byte, dan potongan 1K, sekali lagi menggunakan bit-mask untuk memutuskan blok apa yang digunakan atau tersedia.
Kedua opsi ini berhasil mengurangi overhead informasi akuntansi dan untuk meningkatkan kecepatan
malloc
danfree
(tidak perlu menyatukan blok yang berdekatan ketika membebaskan), terutama penting dalam lingkungan tempat kami bekerja.sumber
malloc
adalah bahwa ia memberi Anda, untuk kasus yang berhasil, satu blok memori setidaknya sebesar yang Anda minta. Masing-masing blok berdekatan dalam hal bagaimana Anda mengakses elemen di dalamnya, tetapi tidak ada persyaratan bahwa arena dari mana blok berasal berdekatan.void *x = malloc(200); free(x, 500);
yang tidak akan berakhir dengan baik :-) Dalam kasus apapun, untuk efisiensi, yang sebenarnya ukuran buffer mungkin lebih besar (Anda hanya tidak bisa mengandalkan ini).Dari
comp.lang.c
daftar FAQ: Bagaimana gratis tahu berapa byte hingga gratis?Implementasi malloc / free mengingat ukuran setiap blok saat dialokasikan, sehingga tidak perlu mengingatkannya tentang ukuran ketika membebaskan. (Biasanya, ukuran disimpan berdekatan dengan blok yang dialokasikan, itulah sebabnya hal-hal biasanya rusak parah jika batas-batas blok yang dialokasikan bahkan sedikit melampaui batas)
sumber
free
. Mungkin jawabannya tidak memuaskan Anda, tetapi saya tidak berpikir Anda akan mendapatkannya dengan info yang lebih umum berlaku :-)Jawaban ini dipindahkan dari Bagaimana free () tahu berapa banyak memori yang harus dialokasikan? di mana saya dicegah untuk menjawab dengan pertanyaan duplikat yang jelas. Maka jawaban ini harus relevan dengan duplikat ini:
Untuk kasus
malloc
, pengalokasi tumpukan menyimpan pemetaan dari pointer dikembalikan asli, untuk rincian yang relevan diperlukan untukfree
memori nanti. Ini biasanya melibatkan penyimpanan ukuran wilayah memori dalam bentuk apa pun yang relevan dengan pengalokasi yang digunakan, misalnya ukuran mentah, atau simpul dalam pohon biner yang digunakan untuk melacak alokasi, atau jumlah "unit" memori yang digunakan.free
tidak akan gagal jika Anda "mengganti nama" pointer, atau menggandakannya dengan cara apa pun. Namun referensi tidak dihitung, dan hanya yang pertama yangfree
akan benar. Tambahanfree
adalah kesalahan "bebas ganda".Mencoba
free
setiap penunjuk dengan nilai yang berbeda dengan yang dikembalikan olehmalloc
s sebelumnya , dan yang belum diperbaiki adalah kesalahan. Tidak dimungkinkan untuk membebaskan sebagian wilayah memori yang kembali darimalloc
.sumber
Pada catatan terkait, pustaka GLib memiliki fungsi alokasi memori yang tidak menyimpan ukuran implisit - dan kemudian Anda hanya meneruskan parameter ukurannya menjadi bebas. Ini dapat menghilangkan bagian dari overhead.
sumber
malloc()
danfree()
tergantung pada sistem / kompiler sehingga sulit untuk memberikan jawaban yang spesifik.Informasi lebih lanjut tentang pertanyaan lain ini .
sumber
Manajer tumpukan menyimpan jumlah memori milik blok yang dialokasikan di suatu tempat ketika Anda menelepon
malloc
.Saya tidak pernah menerapkannya sendiri, tetapi saya kira memori tepat di depan blok yang dialokasikan mungkin berisi informasi meta.
sumber
Teknik asli adalah untuk mengalokasikan blok yang sedikit lebih besar dan menyimpan ukuran di awal, lalu berikan aplikasi sisa blog. Ruang ekstra menampung ukuran dan mungkin tautan untuk menyatukan blok gratis untuk digunakan kembali.
Namun ada beberapa masalah dengan trik-trik itu, seperti cache yang buruk dan perilaku manajemen memori. Menggunakan memori tepat di blok cenderung halaman hal-hal yang tidak perlu dan juga membuat halaman kotor yang mempersulit berbagi dan copy-on-write.
Jadi teknik yang lebih maju adalah menyimpan direktori terpisah. Pendekatan eksotis juga telah dikembangkan di mana area memori menggunakan kekuatan dua ukuran yang sama.
Secara umum, jawabannya adalah: struktur data terpisah dialokasikan untuk menjaga status.
sumber
Untuk menjawab bagian kedua dari pertanyaan Anda: ya, Anda bisa, dan pola yang cukup umum di C adalah sebagai berikut:
sumber
Ketika kita memanggil malloc, itu hanya mengkonsumsi lebih banyak byte dari persyaratannya. Konsumsi byte lebih ini berisi informasi seperti jumlah cek, ukuran dan informasi tambahan lainnya. Ketika kami menelepon gratis pada saat itu langsung ke informasi tambahan di mana ia menemukan alamat dan juga menemukan berapa banyak blok akan bebas.
sumber
untuk menjawab pertanyaan kedua, ya Anda bisa (jenis) menggunakan teknik yang sama seperti
malloc()
dengan hanya menugaskan sel pertama di dalam setiap array ke ukuran array. yang memungkinkan Anda mengirim array tanpa mengirim argumen ukuran tambahan.sumber