国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

c /c++復習筆記 第二天

2019-11-08 18:42:42
字體:
來源:轉載
供稿:網友

內存管理一錯誤處理通過函數的返回值表示錯誤范例badc范例nullc范例failc代碼errorc通過errno表示錯誤范例errnoc范例iferrc二環境變量環境表環境變量函數范例envc三內存管理四進程映像范例mapsc五虛擬內存范例vmc范例crashc范例pagec六內存管理APIs增量方式分配虛擬內存修改虛擬內存塊末尾地址范例brkcmallocc創建虛擬內存到物理內存或文件的映射范例mmapc

內存管理

一、錯誤處理


1. 通過函數的返回值表示錯誤

~~~~~~~~~~~~~~~~~~~~~~~

1) 返回合法值表示成功,返回非法值表示失敗。

范例:bad.c

#include <stdio.h>#include <limits.h>// 獲取文件大小// 成功返回文件的字節數,失敗返回-1long fsize (const char* path) { FILE* fp = fopen (path, "r"); if (! fp) return -1; fseek (fp, 0, SEEK_END); long size = ftell (fp); fclose (fp); return size;}int main (void) { PRintf ("文件路徑:"); char path[PATH_MAX+1]; scanf ("%s", path); long size = fsize (path); if (size == -1) { printf ("文件大小獲取失敗!/n"); return -1; } printf ("文件大小:%ld字節/n", size); return 0;}

2) 返回有效指針表示成功, 返回空指針(NULL/0xFFFFFFFF)表示失敗。

范例:null.c

#include <stdio.h>#include <string.h>// 求字符串的最大值// 成功返回參數字符串中的最大值,失敗返回NULLconst char* strmax (const char* a, const char* b) { return a && b ? (strcmp (a, b) > 0 ? a : b) : NULL;}int main (void) {// const char* max = strmax ("hello", "world"); const char* max = strmax ("hello", NULL); if (! max) { printf ("求字符串最大值失敗!/n"); return -1; } printf ("字符串最大值:%s/n", max); return 0;}

3) 返回0表示成功,返回-1表示失敗, 不輸出數據或通過指針/引用型參數輸出數據。

范例:fail.c

#include <stdio.h>// 整數取模// 成功返回0,失敗返回-1int intmod (int a, int b, int* mod) { if (b == 0) return -1; *mod = a % b; return 0;}int main (void) { printf ("兩個整數:"); int a, b; scanf ("%d%d", &a, &b); int mod; if (intmod (a, b, &mod) == -1) { printf ("整數取模失敗!/n"); return -1; } printf ("整數取模:%d/n", mod); return 0;}

4) 永遠成功,如:printf()。

練習:實現四個函數 slen() - 求字符串的長度,若為空指針,則報錯。 scpy() - 字符串拷貝,考慮緩沖區溢出, 成功返回目標緩沖區地址, 目標緩沖區無效時報錯。 intmin() - 求兩個整數的最小值,若二者相等,則報錯。 intave() - 求兩個整數的平均值,考慮求和溢出, 該函數不會失敗。

代碼:error.c

#include <stdio.h>#define min(a,b) ((a)<(b)?(a):(b))// 求字符串長度// 成功返回字符串長度,失敗返回(size_t)-1size_t slen (const char* s) { if (! s) return -1; size_t len; for (len = 0; s[len]; ++len); return len;}// 字符串拷貝// 成功返回目標字符串,失敗返回NULLchar* scpy (char* dst, size_t size, const char* src) { if (! dst || ! size || ! src) return NULL; if (dst != src) { size_t i, count = min (size - 1, slen (src)); if (dst > src) for (i = 0; i < count; ++i) dst[count-1-i] = src[count-1-i]; else for (i = 0; i < count; ++i) dst[i] = src[i]; dst[count] = '/0'; } return dst;}// 求整數最小值,兩個數相等視作失敗// 成功返回0,失敗返回-1int intmin (int a, int b, int* min) { if (a == b) return -1; *min = a < b ? a : b; return 0;}// 求整數平均值// 永遠成功,不會失敗int intave (int a, int b) { return (a & b) + ((a ^ b) >> 1);}int main (void) {#ifndef ERROR size_t len = slen ("Hello, World !");#else size_t len = slen (NULL);#endif if (len == -1) printf ("求字符串長度失敗!/n"); else printf ("字符串長度:%u/n", len); char dst[5];#ifndef ERROR if (! scpy (dst, sizeof (dst) / sizeof (dst[0]), "0123456789"))#else if (! scpy (NULL, 0, "0123456789"))#endif printf ("字符串拷貝失敗!/n"); else printf ("字符串副本:%s/n", dst); int min;#ifndef ERROR if (intmin (-1, 0, &min) == -1)#else if (intmin (-1, -1, &min) == -1)#endif printf ("求整數最小值失敗!/n"); else printf ("整數最小值:%d/n", min); printf ("整數平均值:%d/n", intave (1234, 5678)); return 0;}

2. 通過errno表示錯誤

~~~~~~~~~~~~~~~~

#include <errno.h>

1) 根據errno得到錯誤編號。

2) 將errno轉換為有意義的字符串:

#include <string.h>char* strerror (int errnum);#include <stdio.h>void perror (const char* s);printf ("%m");

范例:errno.c

#include <stdio.h>#include <string.h>#include <errno.h>int main (void) { FILE* fp = fopen ("none", "r"); if (! fp) { printf ("fopen出錯了:%d/n", errno); printf ("fopen出錯了:%s/n", strerror (errno)); perror ("fopen出錯了"); printf ("fopen出錯了:%m/n"); return -1; } // ... fclose (fp); return 0;}

3) errno在函數執行成功的情況下不會被修改, 因此不能以errno非零,作為發生錯誤判斷依據。

范例:iferr.c

#include <stdio.h>#include <errno.h>void foo (void) { fopen ("none", "r");}int main (void) { foo (); FILE* fp = fopen ("/etc/passwd", "r"); if (errno) { perror ("fopen"); printf ("%p/n", fp); return -1; } // ... fclose (fp); return 0;}

4) errno是一個全局變量,其值隨時可能發生變化。

二、環境變量


1. 環境表

~~~~~

1) 每個程序都會接收到一張環境表, 是一個以NULL指針結尾的字符指針數組。

2) 全局變量environ保存環境表的起始地址。

environ-->---: HOME=/rootenviron-->---: SHELL=/bin/bashenviron-->---: PATH=/bin:/usr/bin:...:.environ-->---: |----|-----|

圖示:env_list.bmp

2. 環境變量函數

~~~~~~~~~~~

#include <stdlib.h>

環境變量:name=value

getenv - 根據name獲得value。

putenv - 以name=value的形式設置環境變量, name不存在就添加,存在就覆蓋其value。

setenv - 根據name設置value,注意最后一個參數表示, 若name已存在是否覆蓋其value。

unsetenv - 刪除環境變量。

clearenv - 清空環境變量,environ==NULL。

范例:env.c

#include <stdio.h>#include <stdlib.h>void printenv (void) { printf ("---- 環境變量 ----/n"); extern char** environ; char** env; for (env = environ; env && *env; ++env) printf ("%s/n", *env); printf ("------------------/n");}int main (void) { char env[256]; const char* name="MYNAME"; // 添加環境變量 sprintf (env, "%s=minwei", name); putenv (env); printf ("%s=%s/n", name, getenv (name)); // 修改環境變量 sprintf (env, "%s=bjarne", name); putenv (env); printf ("%s=%s/n", name, getenv (name)); // 不存在就添加,存在不覆蓋 setenv (name, "minwei", 0); printf ("%s=%s/n", name, getenv (name)); // 不存在就添加,存在就覆蓋 setenv (name, "minwei", 1); printf ("%s=%s/n", name, getenv (name)); printenv (); // 刪除環境變量 unsetenv (name); printenv (); // 清空環境變量 clearenv (); printenv (); return 0;}

三、內存管理


+—-+——–+—————————-+———-+ | 用 | STL | 自動分配/釋放內存資源 | 調C++ | |? ? | C++ | new/delete,構造/析構 | 調標C | | 戶 | 標C | malloc/calloc/realloc/free | 調POSIX | | ? ?| POSIX | brk/sbrk | 調linux | | 層 | Linux | mmap/munmap | 調Kernel | +—-+——–+—————————-+———-+ | 系 | Kernel | kmalloc/vmalloc | 調Driver | | 統 | Driver | get_free_page?? | … | | 層 | ? … ? | ? … ? |? … ? | +—-+——–+—————————-+———-+

四、進程映像


程序是保存在磁盤上的可執行文件。

運行程序時,需要將可執行文件加載到內存,形成進程。

一個程序(文件)可以同時存在多個進程(內存)。

進程在內存空間中的布局就是進程映像。 從低地址到高地址依次為:

代碼區(text):可執行指令、字面值常量、 具有常屬性的全局和靜態局部變量。只讀。

數據區(data):初始化的全局和靜態局部變量。

BSS區:未初始化的全局和靜態局部變量。 進程一經加載此區即被清0。

數據區和BSS區有時被合稱為全局區或靜態區。

堆區(heap):動態內存分配。從低地址向高地址擴展。

棧區(stack):非靜態局部變量, 包括函數的參數和返回值。從高地址向低地址擴展。

堆區和棧區之間存在一塊間隙, 一方面為堆和棧的增長預留空間, 同時共享庫、共享內存等亦位于此。

命令行參數與環境區:命令行參數和環境變量。

圖示:maps.bmp

范例:maps.c

#include <stdio.h>#include <stdlib.h>#include <unistd.h>const int const_global = 10; // 常全局變量int init_global = 10; // 初始化全局變量int uninit_global; // 未初始化全局變量int main (int argc, char* argv[]) { const static int const_static = 10; // 常靜態變量 static int init_static = 10; // 初始化靜態變量 static int uninit_static; // 未初始化靜態變量 const int const_local = 10; // 常局部變量 int prev_local; // 前局部變量 int next_local; // 后局部變量 int* prev_heap = malloc (sizeof (int)); // 前堆變量 int* next_heap = malloc (sizeof (int)); // 后堆變量 const char* literal = "literal"; // 字符串字面值 extern char** environ; // 環境變量 printf ("---- 命令行參數與環境變量 ---- <高>/n"); printf (" 環境變量:%p/n", environ); printf (" 命令行參數:%p/n", argv); printf ("-------------- 棧 ------------/n"); printf (" 常局部變量:%p/n", &const_local); printf (" 前局部變量:%p/n", &prev_local); printf (" 后局部變量:%p/n", &next_local); printf ("-------------- 堆 ------------/n"); printf (" 后堆變量:%p/n", next_heap); printf (" 前堆變量:%p/n", prev_heap); printf ("------------- BSS ------------/n"); printf (" 未初始化全局變量:%p/n", &uninit_global); printf (" 未初始化靜態變量:%p/n", &uninit_static); printf ("------------ 數據 ------------/n"); printf (" 初始化靜態變量:%p/n", &init_static); printf (" 初始化全局變量:%p/n", &init_global); printf ("------------ 代碼 ------------/n"); printf (" 常靜態變量:%p/n", &const_static); printf (" 字面值常量:%p/n", literal); printf (" 常全局變量:%p/n", &const_global); printf (" 函數:%p/n", main); printf ("------------------------------ <低>/n"); printf ("查看/proc/%u/maps,按<回車>退出...", getpid ()); getchar (); return 0;}

比對/proc//maps

》#size a.out

text data ??bss?? ??? ?dec ?? ??hex ?? ??filename 2628 268 ??28?? ??? ?2924?? ??b6c ?? ??a.out ?|?? ?? ?|??? ??|????? ??? ?|?? ??? ??|????? ?? | +———+———+??(10)????+———+———+ (16) ?? ?????V?? ??? ???????????? ? ? ?^ ????????+————————————+ ?????????????????? (+)

五、虛擬內存


每個進程都有各自互獨立的4G字節虛擬地址空間。

用戶程序中使用的都是虛擬地址空間中的地址, 永遠無法直接訪問實際物理內存地址。

虛擬內存到物理內存的映射由操作系統動態維護。

虛擬內存一方面保護了操作系統的安全, 另一方面允許應用程序, 使用比實際物理內存更大的地址空間。

圖示:vm.png

4G進程地址空間分成兩部分: [0, 3G)為用戶空間, 如某棧變量的地址0xbfc7fba0=3,217,554,336,約3G; [3G, 4G)為內核空間。

用戶空間中的代碼, 不能直接訪問內核空間中的代碼和數據, 但可以通過系統調用進入內核態, 間接地與系統內核交互。

圖示:kernel.png %207.%20對內存的越權訪問,%20%20%20%20或試圖訪問沒有映射到物理內存的虛擬內存,%20%20%20%20將導致段錯誤。

用戶空間對應進程,進程一切換,用戶空間即隨之變化。%20內核空間由操作系統內核管理,不會隨進程切換而改變。%20內核空間由內核根據獨立且唯一的頁表init_mm.pgd%20進行內存映射,而用戶空間的頁表則每個進程一份。

每個進程的內存空間完全獨立。%20不同進程之間交換虛擬內存地址是毫無意義的。

范例:vm.c#include%20<stdio.h>int%20g_vm%20=%200;int%20main%20(void)%20{%20%20%20%20printf%20("&g_vm%20=%20%p/n",%20&g_vm);%20%20%20%20printf%20("整數:");%20%20%20%20scanf%20("%d%*c",%20&g_vm);%20%20%20%20printf%20("啟動另一個進程,輸入不同的數據,"%20%20%20%20%20%20%20%20"按<回車>繼續...");%20%20%20%20getchar%20();%20%20%20%20printf%20("g_vm%20=%20%d/n",%20g_vm);%20%20%20%20return%200;}標準庫內部通過一個雙向鏈表,%20管理在堆中動態分配的內存。%20malloc函數分配內存時會附加若干(通常是12個)字節,%20存放控制信息。%20該信息一旦被意外損壞,可能在后續操作中引發異常。范例:crash.c#include%20<stdio.h>#include%20<stdlib.h>int%20main%20(void)%20{%20%20%20%20int*%20p1%20=%20malloc%20(sizeof%20(int));%20%20%20%20int*%20p2%20=%20malloc%20(sizeof%20(int));%20%20%20%20printf%20("%p,%20%p/n",%20p1,%20p2);%20%20%20%20free%20(p2);%20%20%20%20p1[3]%20=%200;%20%20%20%20free%20(p1);%20%20%20%20return%200;}虛擬內存到物理內存的映射以頁(4K=4096字節)為單位。%20通過malloc函數首次分配內存,至少映射33頁。%20即使通過free函數釋放掉全部內存,%20最初的33頁仍然保留。

圖示:address_space.png

#include <unistd.h>int getpagesize (void);

返回內存頁的字節數。

范例:page.c

#include <stdio.h>#include <stdlib.h>#include <unistd.h>void presskey (void) { printf ("查看/proc/%u/maps,按<回車>繼續...", getpid ()); getchar ();}int main (void) { printf ("1頁 = %d字節/n", getpagesize ()); char* pc = malloc (sizeof (char)); printf ("pc = %p/n", pc); presskey (); free (pc); printf ("free(%p)/n", pc); presskey (); pc = malloc (sizeof (char) * 100); printf ("pc = %p/n", pc); presskey (); setbuf (stdout, NULL); size_t i = 0; for (;;) { printf ("向堆內存%p寫...", &pc[i]); printf ("%c/n", pc[i++] = (i % 26) + 'A'); } return 0;}

分析: char* pc = malloc (sizeof (char)); | v<————— 33頁 —————>| ——+——-+———-+——————-+—— | 1字節 | 控制信息 | | ——+——-+———-+——————-+—— ^ ^ ^ ^ ^ 段錯誤 OK 后續錯誤 不穩定 段錯誤

六、內存管理APIs


1. 增量方式分配虛擬內存

~~~~~~~~~~~~~~~~~~~

#include <unistd.h>void* sbrk ( intptr_t increment // 內存增量(以字節為單位));

返回上次調用brk/sbrk后的末尾地址,失敗返回-1。

increment取值:

0 - 獲取末尾地址。

0 - 增加內存空間。

<0 - 釋放內存空間。

內部維護一個指針, 指向當前堆內存最后一個字節的下一個位置。 sbrk函數根據增量參數調整該指針的位置, 同時返回該指針原來的位置。 若發現頁耗盡或空閑,則自動追加或取消頁映射。

void* p=sbrk(4); p=sbrk(0); ^ ^ | | 返回 – increment -> 返回 | | v v –+—+—+—+—+—+—+– | B | B | B | B | B | B | –+—+—+—+—+—+—+– |<——— 頁 ——–

2. 修改虛擬內存塊末尾地址

~~~~~~~~~~~~~~~~~~~~~

#include <unistd.h>int brk ( void* end_data_segment // 內存塊末尾地址);

成功返回0,失敗返回-1。

內部維護一個指針, 指向當前堆內存最后一個字節的下一個位置。 brk函數根據指針參數設置該指針的位置。 若發現頁耗盡或空閑,則自動追加或取消頁映射。

void* p=sbrk(0); brk(p+4); ^ | | v 返回 * * 設置 | | v v –+—+—+—+—+—+—+– | B | B | B | B | B | B | –+—+—+—+—+—+—+– |<——— 頁 ——–

sbrk/brk底層維護一個指針位置, 以頁(4K)為單位分配和釋放虛擬內存。 簡便起見,可用sbrk分配內存,用brk釋放內存。

范例:brk.c、malloc.c

brk.c#include <stdio.h>#include <unistd.h>void presskey (void) { printf ("查看/proc/%u/maps,按<回車>繼續...", getpid ()); getchar ();}int main (void) { void* p1 = sbrk (4); // RXXX ---- ---- ---- - printf ("p1 = %p/n", p1); void* p2 = sbrk (4); // XXXX RXXX ---- ---- - printf ("p2 = %p/n", p2); void* p3 = sbrk (4); // XXXX XXXX RXXX ---- - printf ("p3 = %p/n", p3); void* p4 = sbrk (4); // XXXX XXXX XXXX RXXX - printf ("p4 = %p/n", p4); void* p5 = sbrk (0); // XXXX XXXX XXXX XXXX R printf ("p5 = %p/n", p5); int* pn = (int*)p1; pn[0] = 0; pn[1] = 1; pn[2] = 2; pn[3] = 3; pn[1023] = 1023; printf ("%d, %d, %d, %d, %d/n", pn[0], pn[1], pn[2], pn[3], pn[1023]);// pn[1024] = 1024; void* p6 = sbrk (-8); // XXXX XXXX ---- ---- R printf ("p6 = %p/n", p6); void* p7 = sbrk (-8); // ---- ---- R--- ---- - printf ("p7 = %p/n", p7); printf ("--------/n"); int page = getpagesize (); printf ("%p/n", sbrk (page)); presskey (); printf ("%p/n", sbrk (1)); presskey (); printf ("%p/n", sbrk (-1)); presskey (); printf ("%p/n", sbrk (-page)); presskey (); printf ("--------/n"); p1 = sbrk (0); // R--- ---- ---- ---- - printf ("p1 = %p/n", p1); brk (p2 = p1 + 4); // XXXX S--- ---- ---- - printf ("p2 = %p/n", p2); brk (p3 = p2 + 4); // XXXX XXXX S--- ---- - printf ("p3 = %p/n", p3); brk (p4 = p3 + 4); // XXXX XXXX XXXX S--- - printf ("p4 = %p/n", p4); brk (p5 = p4 + 4); // XXXX XXXX XXXX XXXX S printf ("p5 = %p/n", p5); pn = (int*)p1; pn[0] = 0; pn[1] = 1; pn[2] = 2; pn[3] = 3; pn[1023] = 1023; printf ("%d, %d, %d, %d, %d/n", pn[0], pn[1], pn[2], pn[3], pn[1023]);// pn[1024] = 1024; brk (p3); // XXXX XXXX S--- ---- - brk (p1); // S--- ---- ---- ---- -// pn[0] = 0; printf ("--------/n"); void* begin = sbrk (sizeof (int)); if ((int)begin == -1) { perror ("sbrk"); return -1; } pn = (int*)begin; *pn = 1234; double* pd = (double*)sbrk (sizeof (double)); if ((int)pd == -1) { perror ("sbrk"); return -1; } *pd = 3.14; char* psz = (char*)sbrk (256 * sizeof (char)); if ((int)psz == -1) { perror ("sbrk"); return -1; } sprintf (psz, "Hello, World !"); printf ("%d, %g, %s/n", *pn, *pd, psz); if (brk (begin) == -1) { perror ("brk"); return -1; } return 0;}malloc.c#include <stdio.h>#include <stdbool.h>#include <unistd.h>// 內存控制塊typedef struct mem_control_block { bool free; // 自由標志 struct mem_control_block* prev; // 前塊指針 size_t size; // 本塊大小} MCB;MCB* g_top = NULL; // 棧頂指針// 分配內存void* my_malloc (size_t size) { MCB* mcb; for (mcb = g_top; mcb; mcb = mcb->prev) if (mcb->free && mcb->size >= size) break; if (! mcb) { mcb = sbrk (sizeof (MCB) + size); if (mcb == (void*)-1) return NULL; mcb->prev = g_top; mcb->size = size; g_top = mcb; } mcb->free = false; return mcb + 1;}// 釋放內存void my_free (void* ptr) { if (! ptr) return; MCB* mcb = (MCB*)ptr - 1; mcb->free = true; for (mcb = g_top; mcb->prev; mcb = mcb->prev) if (! mcb->free) break; if (mcb->free) { g_top = mcb->prev; brk (mcb); } else if (mcb != g_top) { g_top = mcb; brk ((void*)mcb + sizeof (mcb) + mcb->size); }}int main (void) { int* pa[10]; size_t size = sizeof (pa) / sizeof (pa[0]), i, j; for (i = 0; i < size; ++i) { if (! (pa[i] = my_malloc((i+1)*sizeof(int)))) { perror ("my_malloc"); return -1; } for (j = 0; j <= i; ++j) pa[i][j] = j; } for (i = 0; i < size; ++i) { for (j = 0; j <= i; ++j) printf ("%d ", pa[i][j]); printf ("/n"); } /* for (i = 0; i < size; ++i) my_free (pa[i]); */ for (;;) { my_free (pa[--i]); if (! i) break; } return 0;}

3. 創建虛擬內存到物理內存或文件的映射

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#include <sys/mman.h>void* mmap ( void* start, // 映射區內存起始地址, // NULL系統自動選定,成功返回之 size_t length, // 字節長度,自動按頁(4K)對齊 int prot, // 映射權限 int flags, // 映射標志 int fd, // 文件描述符 off_t offset // 文件偏移量,自動按頁(4K)對齊);

成功返回映射區內存起始地址,失敗返回MAP_FAILED(-1)。

prot取值:

PROT_EXEC - 映射區域可執行。

PROT_READ - 映射區域可讀取。

PROT_WRITE - 映射區域可寫入。

PROT_NONE - 映射區域不可訪問。

flags取值:

MAP_FIXED - 若在start上無法創建映射, 則失敗(無此標志系統會自動調整)。

MAP_SHARED - 對映射區域的寫入操作直接反映到文件中。

MAP_PRIVATE - 對映射區域的寫入操作只反映到緩沖區中, 不會真正寫入文件。

MAP_ANONYMOUS - 匿名映射, 將虛擬地址映射到物理內存而非文件, 忽略fd。

MAP_DENYWRITE - 拒絕其它對文件的寫入操作。

MAP_LOCKED - 鎖定映射區域,保證其不被置換。

銷毀虛擬內存到物理內存或文件的映射 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

int munmap ( void* start, // 映射區內存起始地址 size_t length, // 字節長度,自動按頁(4K)對齊 );

成功返回0,失敗返回-1。

范例:mmap.c

#include <stdio.h>#include <unistd.h>#include <sys/mman.h>#define MAX_TEXT 256int main (void) { char* psz = (char*)mmap ( NULL, MAX_TEXT * sizeof (char), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); if (psz == MAP_FAILED) { perror ("mmap"); return -1; } sprintf (psz, "Hello, Memory !"); printf ("%s/n", psz); printf ("psz = %p/n", psz); printf ("查看/proc/%u/maps,按<回車>退出...", getpid ()); getchar (); if (munmap (psz, MAX_TEXT * sizeof (char)) == -1) { perror ("munmap"); return -1; } return 0;}

mmap/munmap底層不維護任何東西,只是返回一個首地址, 所分配內存位于堆中。

brk/sbrk底層維護一個指針,記錄所分配的內存結尾, 所分配內存位于堆中,底層調用mmap/munmap。

malloc底層維護一個雙向鏈表和必要的控制信息, 不可越界訪問,所分配內存位于堆中,底層調用brk/sbrk。

每個進程都有4G的虛擬內存空間, 虛擬內存地址只是一個數字, 并沒有和實際的物理內存將關聯。 所謂內存分配與釋放, 其本質就是建立或取消虛擬內存和物理內存間的映射關系。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

主站蜘蛛池模板: 彰化市| 潞西市| 遵义市| 新兴县| 太仆寺旗| 福建省| 南和县| 北流市| 大新县| 新平| 红桥区| 彰化市| 馆陶县| 安图县| 武邑县| 鹤岗市| 嵩明县| 永修县| 大厂| 舒兰市| 临泽县| 常熟市| 彩票| 铜鼓县| 会宁县| 文成县| 临桂县| 耒阳市| 喜德县| 四川省| 鹤山市| 长沙市| 灵宝市| 普洱| 菏泽市| 涿鹿县| 原平市| 苏尼特右旗| 广安市| 莎车县| 苗栗市|