Dalam sistem pengendalian Linux, bahagian dalam ruang alamat maya dibahagikan kepada dua bahagian: ruang kernel dan ruang pengguna Sistem dengan digit yang berbeza mempunyai julat ruang alamat yang berbeza. Sebagai contoh, sistem 32-bit dan 64-bit yang paling biasa adalah seperti berikut:
Anda boleh lihat di sini:
Mari kita bincangkan tentang perbezaan antara ruang kernel dan ruang pengguna:
Walaupun setiap proses mempunyai memori maya bebasnya sendiri, Alamat kernel dalam setiap memori maya sebenarnya dikaitkan dengan memori fizikal yang sama. Dengan cara ini, selepas proses bertukar kepada keadaan kernel, ia boleh mengakses memori ruang kernel dengan mudah.
Seterusnya, mari kita ketahui lebih lanjut tentang pembahagian ruang maya dan ruang kernel dibahagikan dengan cara yang berbeza.
Mari kita lihat pengagihan ruang pengguna dengan mengambil sistem 32-bit sebagai contoh, saya melukis gambar untuk mewakili hubungan mereka:
.Anda boleh lihat dari gambar ini bahawa memori ruang pengguna dibahagikan kepada 6 segmen memori berbeza dari rendah ke tinggi:
Di antara 6 segmen memori ini, memori segmen pemetaan timbunan dan fail diperuntukkan secara dinamik. Contohnya, menggunakan malloc() atau mmap() pustaka standard C, anda boleh memperuntukkan memori secara dinamik dalam segmen pemetaan timbunan dan fail masing-masing.
Sebenarnya, malloc() bukan panggilan sistem, tetapi fungsi dalam perpustakaan C, digunakan untuk memperuntukkan memori secara dinamik.
Apabila malloc menggunakan memori, terdapat dua cara untuk memohon memori timbunan daripada sistem pengendalian.
Pelaksanaan kaedah satu sangat mudah, iaitu menggunakan fungsi brk() untuk mengalihkan penunjuk "top of heap" ke alamat tinggi untuk mendapatkan ruang ingatan baharu. Seperti yang ditunjukkan di bawah:
Kaedah 2 menggunakan kaedah "pemetaan tanpa nama persendirian" dalam panggilan sistem mmap() untuk memperuntukkan sekeping memori dalam kawasan pemetaan fail, iaitu untuk "mencuri" sekeping memori daripada kawasan pemetaan fail. Seperti yang ditunjukkan di bawah:
"
Dalam keadaan apakah malloc() memperuntukkan memori melalui brk()? Dalam senario apakah memori diperuntukkan melalui mmap()?
”
malloc() mempunyai ambang yang ditentukan secara lalai dalam kod sumber:
Perhatikan bahawa versi glibc yang berbeza mentakrifkan ambang yang berbeza.
malloc() memperuntukkan ingatan fizikal?
Tidak, malloc() memperuntukkan memori maya.
Jika memori maya yang diperuntukkan tidak diakses, memori maya tidak akan dipetakan ke memori fizikal, jadi ia tidak akan menduduki memori fizikal.
Hanya apabila mengakses ruang alamat maya yang diperuntukkan, sistem pengendalian mencari jadual halaman dan mendapati halaman yang sepadan dengan memori maya tidak berada dalam memori fizikal Ia akan mencetuskan gangguan halaman, dan kemudian sistem pengendalian akan mewujudkan a pautan antara ingatan maya dan hubungan pemetaan fizikal antara.
malloc() memperuntukkan memori, ia tidak memperuntukkan ruang memori mengikut bilangan bait yang dijangkakan oleh pengguna, tetapi pra-peruntukkan ruang yang lebih besar sebagai kolam memori.
Jumlah ruang khusus yang akan diperuntukkan terlebih dahulu adalah berkaitan dengan pengurus memori yang digunakan oleh malloc Kami akan menggunakan pengurus memori lalai malloc (Ptmalloc2) untuk menganalisis.
Seterusnya, mari lakukan percubaan dan gunakan kod berikut untuk melihat berapa banyak ruang memori yang sebenarnya diperuntukkan oleh sistem pengendalian apabila memohon 1 bait memori melalui malloc.
#include #include int main() { printf("使用cat /proc/%d/maps查看内存分配\n",getpid()); //申请1字节的内存 void *addr = malloc(1); printf("此1字节的内存起始地址:%x\n", addr); printf("使用cat /proc/%d/maps查看内存分配\n",getpid()); //将程序阻塞,当输入任意字符时才往下执行 getchar(); //释放内存 free(addr); printf("释放了1字节的内存,但heap堆并不会释放\n"); getchar(); return 0; }
Laksanakan kod (Biar saya terangkan terlebih dahulu, versi perpustakaan glibc yang saya gunakan ialah 2.17):
Kita boleh melihat pengedaran memori proses melalui fail /proc//maps. Saya menapis julat alamat memori dalam fail peta dengan alamat permulaan memori 1-bait ini.
[root@xiaolin ~]# cat /proc/3191/maps | grep d730 00d73000-00d94000 rw-p 00000000 00:00 0 [heap]
Memori yang diperuntukkan dalam contoh ini adalah kurang daripada 128 KB, jadi memori digunakan pada ruang timbunan melalui panggilan sistem brk(), supaya anda boleh melihat tanda [timbunan] di hujung kanan.
Anda dapat melihat bahawa julat alamat memori bagi ruang timbunan ialah 00d73000-00d94000, dan saiz julat ini ialah 132KB, yang bermaksud bahawa malloc(1) sebenarnya pra-peruntukkan 132K bait memori.
Sesetengah pelajar mungkin perasan bahawa alamat permulaan memori yang dicetak dalam program ialah d73010, manakala fail peta menunjukkan bahawa alamat permulaan ruang ingatan timbunan ialah d73000 Mengapakah terdapat tambahan 0x10 (16 bait)? Mari tinggalkan soalan ini buat masa ini dan bincangkannya kemudian.
#percuma Adakah memori yang dibebaskan akan dikembalikan kepada sistem pengendalian?
Mari kita laksanakan proses di atas untuk melihat sama ada memori timbunan masih ada selepas memori dikeluarkan melalui fungsi free()?
Seperti yang anda boleh lihat dari gambar di bawah, selepas membebaskan memori, ingatan timbunan masih wujud dan belum dikembalikan ke sistem pengendalian.
Ini kerana daripada melepaskan 1 bait ini kepada sistem pengendalian, adalah lebih baik untuk menyimpannya di cache dan memasukkannya ke dalam kumpulan memori malloc Apabila proses itu digunakan untuk 1 bait memori sekali lagi, ia boleh digunakan semula secara langsung, yang mana adalah lebih pantas.
Sudah tentu, apabila proses keluar, sistem pengendalian akan menuntut semula semua sumber proses.
Memori timbunan masih wujud selepas ingatan bebas yang dinyatakan di atas adalah untuk ingatan yang digunakan oleh malloc melalui brk().
Jika malloc memohon memori melalui mmap, ia akan dikembalikan kepada sistem pengendalian selepas membebaskan memori secara percuma.
Mari kita lakukan percubaan untuk mengesahkan bahawa kita memohon 128 KB memori melalui malloc, supaya malloc memperuntukkan memori melalui mmap.
#include #include int main() { //申请1字节的内存 void *addr = malloc(128*1024); printf("此128KB字节的内存起始地址:%x\n", addr); printf("使用cat /proc/%d/maps查看内存分配\n",getpid()); //将程序阻塞,当输入任意字符时才往下执行 getchar(); //释放内存 free(addr); printf("释放了128KB字节的内存,内存也归还给了操作系统\n"); getchar(); return 0; }
Kod pelaksanaan:
Melihat pada pengedaran memori proses, anda boleh mendapati bahawa tiada tanda [kepala] di hujung kanan, menunjukkan bahawa memori tanpa nama diperuntukkan daripada kawasan pemetaan fail melalui mmap melalui pemetaan tanpa nama.
Kemudian mari kita bebaskan ingatan ini dan lihat:
Semak alamat permulaan memori 128 KB sekali lagi dan anda boleh mendapati ia tidak lagi wujud, menunjukkan bahawa ia telah dikembalikan kepada sistem pengendalian.
Berkenaan soalan "Adakah memori yang dipohon oleh malloc dan dikeluarkan secara percuma akan dikembalikan ke sistem pengendalian?", kita boleh membuat ringkasan:
Jadi, operasi memohon memori harus mengelakkan panggilan sistem yang kerap Jika mmap digunakan untuk memperuntukkan memori, bermakna panggilan sistem mesti dilaksanakan setiap kali.
Selain itu, kerana memori yang diperuntukkan oleh mmap akan dikembalikan kepada sistem pengendalian setiap kali ia dikeluarkan, jadi alamat maya yang diperuntukkan oleh mmap berada dalam keadaan kesalahan halaman setiap kali, dan kemudian apabila alamat maya diakses untuk yang pertama masa, ia akan dicetuskan gangguan halaman.
Dalam erti kata lain,
jika memori kerap diperuntukkan melalui mmap, bukan sahaja keadaan berjalan akan ditukar setiap kali, malah gangguan halaman juga akan berlaku (selepas akses pertama ke alamat maya), yang akan menghasilkan CPU yang besar penggunaan.
Untuk memperbaiki kedua-dua masalah ini, apabila malloc menggunakan memori dalam ruang timbunan melalui panggilan sistem brk(), memandangkan ruang timbunan berterusan, ia secara langsung memperuntukkan memori yang lebih besar sebagai kumpulan memori apabila memori dilepaskan , ia Dicache dalam kolam memori.
Apabila anda memohon memori pada masa akan datang, cuma keluarkan blok memori yang sepadan terus dari kumpulan memori, dan hubungan pemetaan antara alamat maya dan alamat fizikal blok memori ini bukan sahaja mengurangkan bilangan panggilan sistem, Ia juga mengurangkan bilangan gangguan halaman, yang akan sangat mengurangkan penggunaan CPU.
Jika kita memohon tiga keping memori 10k, 20k, dan 30k berturut-turut, jika 10k dan 20k dilepaskan dan menjadi ruang ingatan percuma, jika memori yang digunakan untuk kali seterusnya kurang daripada 30k, maka ruang memori percuma ini boleh digunakan semula .
Tetapi jika memori yang diminta seterusnya melebihi 30k, tiada ruang memori kosong yang tersedia, dan anda mesti memohon kepada OS, dan memori sebenar yang digunakan akan terus meningkat.
Oleh itu, memandangkan sistem kerap mallocs dan membebaskan, terutamanya untuk blok kecil memori, semakin banyak serpihan yang tidak boleh digunakan akan dijana dalam timbunan, yang membawa kepada "kebocoran memori". Fenomena "kebocoran" ini tidak dapat dikesan menggunakan valgrind.
Jadi, dalam pelaksanaan malloc, perbezaan, kebaikan dan keburukan dalam tingkah laku brk dan mmap dipertimbangkan sepenuhnya, dan blok memori yang besar (128KB) diperuntukkan secara lalai sebelum mmap digunakan untuk memperuntukkan ruang memori.
Ingat, saya nyatakan sebelum ini bahawa alamat permulaan memori yang dikembalikan kepada mod pengguna oleh malloc adalah 16 bait lebih daripada alamat permulaan ruang timbunan proses?
16 bait tambahan menyimpan maklumat perihalan blok memori, seperti saiz blok memori.
Dengan cara ini, apabila fungsi free() dilaksanakan, free akan mengimbangi alamat memori masuk sebanyak 16 bait ke kiri, dan kemudian menganalisis saiz blok memori semasa daripada 16 bait ini, dan secara semula jadi mengetahui betapa besarnya perlu dilepaskan ingatan.
Atas ialah kandungan terperinci Fahami strategi peruntukan memori Linux dalam satu artikel. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!