Contoh runnable minimal
Apa yang dilakukan dengan panggilan sistem brk ()?
Meminta kernel untuk memberi Anda Anda membaca dan menulis ke sepotong memori yang berdekatan yang disebut heap.
Jika Anda tidak bertanya, itu mungkin akan membuat kesalahan Anda.
Tanpa brk:
#define _GNU_SOURCE
#include <unistd.h>
int main(void) {
/* Get the first address beyond the end of the heap. */
void *b = sbrk(0);
int *p = (int *)b;
/* May segfault because it is outside of the heap. */
*p = 1;
return 0;
}
Dengan brk:
#define _GNU_SOURCE
#include <assert.h>
#include <unistd.h>
int main(void) {
void *b = sbrk(0);
int *p = (int *)b;
/* Move it 2 ints forward */
brk(p + 2);
/* Use the ints. */
*p = 1;
*(p + 1) = 2;
assert(*p == 1);
assert(*(p + 1) == 2);
/* Deallocate back. */
brk(b);
return 0;
}
GitHub hulu .
Hal di atas mungkin tidak mengenai halaman baru dan bahkan tanpa segfault brk, jadi di sini adalah versi yang lebih agresif yang mengalokasikan 16MiB dan sangat mungkin untuk melakukan segmentasi tanpa brk:
#define _GNU_SOURCE
#include <assert.h>
#include <unistd.h>
int main(void) {
void *b;
char *p, *end;
b = sbrk(0);
p = (char *)b;
end = p + 0x1000000;
brk(end);
while (p < end) {
*(p++) = 1;
}
brk(b);
return 0;
}
Diuji pada Ubuntu 18.04.
Visualisasi ruang alamat virtual
Sebelum brk:
+------+ <-- Heap Start == Heap End
Setelah brk(p + 2):
+------+ <-- Heap Start + 2 * sizof(int) == Heap End
| |
| You can now write your ints
| in this memory area.
| |
+------+ <-- Heap Start
Setelah brk(b):
+------+ <-- Heap Start == Heap End
Untuk lebih memahami ruang alamat, Anda harus membiasakan diri dengan paging: Bagaimana cara kerja paging x86? .
Mengapa kita membutuhkan keduanya brkdan sbrk?
brktentu saja dapat diimplementasikan dengan sbrkperhitungan + offset, keduanya ada hanya untuk kenyamanan.
Di backend, kernel Linux v5.0 memiliki panggilan sistem tunggal brkyang digunakan untuk mengimplementasikan keduanya: https://github.com/torvalds/linux/blob/v5.0/arch/x86/entry/syscalls/syscall_64. tbl # L23
12 common brk __x64_sys_brk
Apakah brkPOSIX?
brkdulu POSIX, tetapi dihapus pada POSIX 2001, sehingga kebutuhan untuk _GNU_SOURCEmengakses pembungkus glibc.
Penghapusan ini kemungkinan disebabkan oleh pengantar mmap, yang merupakan superset yang memungkinkan beberapa rentang untuk dialokasikan dan lebih banyak opsi alokasi.
Saya pikir tidak ada kasus yang valid di mana Anda harus menggunakan, brkbukan mallocatau mmapsaat ini.
brk vs. malloc
brkadalah salah satu kemungkinan lama implementasi malloc.
mmapadalah mekanisme baru yang lebih kuat yang kemungkinan besar semua sistem POSIX saat ini gunakan untuk mengimplementasikan malloc. Berikut adalah contoh alokasi memori runnable minimalmmap .
Bisakah saya campur brkdan malloc?
Jika Anda mallocdiimplementasikan dengan brk, saya tidak tahu bagaimana itu mungkin tidak dapat meledakkan sesuatu, karena brkhanya mengelola satu rentang memori.
Namun saya tidak dapat menemukan apa pun tentang itu di dokumen glibc, misalnya:
Hal kemungkinan hanya bekerja di sana saya kira karena mmapkemungkinan digunakan untuk malloc.
Lihat juga:
Info lebih lanjut
Secara internal, kernel memutuskan apakah proses dapat memiliki banyak memori, dan menyediakan halaman memori untuk penggunaan itu.
Ini menjelaskan bagaimana tumpukan dibandingkan dengan tumpukan: Apa fungsi instruksi push / pop yang digunakan pada register dalam rakitan x86?