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 brk
dan sbrk
?
brk
tentu saja dapat diimplementasikan dengan sbrk
perhitungan + offset, keduanya ada hanya untuk kenyamanan.
Di backend, kernel Linux v5.0 memiliki panggilan sistem tunggal brk
yang 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 brk
POSIX?
brk
dulu POSIX, tetapi dihapus pada POSIX 2001, sehingga kebutuhan untuk _GNU_SOURCE
mengakses 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, brk
bukan malloc
atau mmap
saat ini.
brk
vs. malloc
brk
adalah salah satu kemungkinan lama implementasi malloc
.
mmap
adalah 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 brk
dan malloc?
Jika Anda malloc
diimplementasikan dengan brk
, saya tidak tahu bagaimana itu mungkin tidak dapat meledakkan sesuatu, karena brk
hanya 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 mmap
kemungkinan 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?