linux內存地址
① linux內存管理--linux內核高端內存
linux內核地址映射模型
x86
CPU採用了段頁式地址映射模型。進程代碼中的地址為邏輯地址,經過段頁式地址映射後,才真正訪問物理內存。
段頁式機制如下圖。
linux內核地址空間劃分
通常32位linux內核地址空間劃分0~3G為用戶空間,3~4G為內核空間。注意這里是32位內核地址空間劃分,64位內核地址空間劃分是不同的。
linux內核高端內存的由來
當內核模塊代碼或線程訪問內存時,代碼中的內存地址都為邏輯地址,而對應到真正的物理內存地址,需要地址一對一的映射,如邏輯地址0xc0000003對應的物理地址為0×3,0xc0000004對應的物理地址為0×4,…
…,邏輯地址與物理地址對應的關系為
物理地址
=
邏輯地址
0xC0000000
邏輯地址物理內存地址0xc00000000×00xc00000010×10xc00000020×20xc00000030×3…
…
0xe00000000×20000000……0xffffffff0×40000000
??
顯然不能將內核地址空間0xc0000000
~
0xfffffff全部用來簡單的地址映射。因此x86架構中將內核地址空間劃分三部分:ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM。ZONE_HIGHMEM即為高端內存,這就是內存高端內存概念的由來。
在x86結構中,三種類型的區域如下:
ZONE_DMA
內存開始的16MB
ZONE_NORMAL
16MB~896MB
ZONE_HIGHMEM
896MB
~
結束
linux內核高端內存的理解
前面我們解釋了高端內存的由來。
linux將內核地址空間劃分為三部分ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM,高端內存HIGH_MEM地址空間范圍為0xF8000000
~
0xFFFFFFFF(896MB~1024MB)。那麼如內核是如何藉助128MB高端內存地址空間是如何實現訪問可以所有物理內存?
當內核想訪問高於896MB物理地址內存時,從0xF8000000
~
0xFFFFFFFF地址空間范圍內找一段相應大小空閑的邏輯地址空間,借用一會。借用這段邏輯地址空間,建立映射到想訪問的那段物理內存(即填充內核PTE頁面表),臨時用一會,用完後歸還。這樣別人也可以借用這段地址空間訪問其他物理內存,實現了使用有限的地址空間,訪問所有所有物理內存。如下圖。
例如內核想訪問2G開始的一段大小為1MB的物理內存,即物理地址范圍為0×80000000
~
0x800FFFFF。訪問之前先找到一段1MB大小的空閑地址空間,假設找到的空閑地址空間為0xF8700000
~
0xF87FFFFF,用這1MB的邏輯地址空間映射到物理地址空間0×80000000
~
0x800FFFFF的內存。映射關系如下:
邏輯地址物理內存地址0xF87000000×800000000xF87000010×800000010xF87000020×80000002…
…0xF87FFFFF0x800FFFFF
當內核訪問完0×80000000
~
0x800FFFFF物理內存後,就將0xF8700000
~
0xF87FFFFF內核線性空間釋放。這樣其他進程或代碼也可以使用0xF8700000
~
0xF87FFFFF這段地址訪問其他物理內存。
從上面的描述,我們可以知道高端內存的最基本思想:借一段地址空間,建立臨時地址映射,用完後釋放,達到這段地址空間可以循環使用,訪問所有物理內存。
看到這里,不禁有人會問:萬一有內核進程或模塊一直佔用某段邏輯地址空間不釋放,怎麼辦?若真的出現的這種情況,則內核的高端內存地址空間越來越緊張,若都被佔用不釋放,則沒有建立映射到物理內存都無法訪問了。
② Linux 內核的內存管理 - 概念
Concepts overview — The Linux Kernel documentation
Linux中的內存管理是一個復雜的系統,經過多年的發展,它包含越來越多的功能,以支持從 MMU-less microcontrollers 到 supercomputers 的各種系統。
沒有MMU內存管理的系統被稱為 nommu ,它值得寫一份專門的文檔進行描述。
盡管有些概念是相同的,這里我們假設MMU可用,CPU可以將虛擬地址轉換為物理地址。
計算機系統中的物理內存是有限資源,即便支持內存熱插拔,其可以安裝的內存也有限的。物理內存不一定必須是連續的;它可以作為一組不同的地址范圍被訪問。此外,不同的CPU架構,甚至同架構的不同實現對如何定義這些地址范圍都是不同的。
這使得直接處理物理內存異常復雜,為了避免這種復雜性,開發了 虛擬內存 (virtual memory) 的概念。
虛擬內存從應用軟體中抽象出物理內存的細節,只允許在物理內存中保留需要的信息 (demand paging) ,並提供一種機制來保護和控制進程之間的數據共享。
通過虛擬內存,每次內存訪問都訪問一個 虛擬地址 。當CPU對從系統內存讀取(或寫入)的指令進行解碼時,它將該指令中編碼的虛擬地址轉換為內存控制器可以理解的物理地址。
物理內存被切分為 頁幀 page frames 或 頁 pages 。頁的大小是基於架構的。一些架構允許從幾個支持的值中選擇頁大小;此選擇在內核編譯時設置到內核配置。
每個物理內存頁都可以映射為一個或多個 虛擬頁(virtual pages) 。映射關系描述在 頁表(page tables) 中,頁表將程序使用的虛擬地址轉換為物理內存地址。頁表以層次結構組織。
最底層的表包含軟體使用的實際內存頁的物理地址。較高層的表包含較低層表頁的物理地址。頂層表的指針駐留在寄存器中。
當CPU進行地址轉換的時候,它使用寄存器訪問頂級頁表。
虛擬地址的高位,用於頂級頁表的條目索引。然後,通過該條目訪問下級,下級的虛擬地址位又作為其下下級頁表的索引。虛擬地址的最低位定義實際頁內的偏移量。
地址轉換需要多次內存訪問,而內存訪問相對於CPU速度來說比較慢。為了避免在地址轉換上花費寶貴的處理器周期,CPU維護著一個稱為 TLB (Translation Lookaside Buffer)的用於地址轉換緩存(cache)。通常TLB是非常稀缺的資源,需要大內存工作應用程序會因為TLB未命中而影響性能。
很多現代CPU架構允許頁表的高層直接映射到內存頁。例如,x86架構,可以通過二級、三級頁表的條目映射2M甚至1G內存頁。在Linux中,這些內存頁稱為 大頁 (Huge) 。大頁的使用顯著降低了TLB的壓力,提高了TLB命中率,從而提高了系統的整體性能。
Linux提供兩種機制開啟使用大頁映射物理內存。
第一個是 HugeTLB 文件系統,即 hugetlbfs 。它是一個偽文件系統,使用RAM作為其存儲。在此文件系統中創建的文件,數據駐留在內存中,並使用大頁進行映射。
關於 HugeTLB Pages
另一個被稱為 THP (Transparent HugePages) ,後出的開啟大頁映射物理內存的機制。
與 hugetlbfs 不同,hugetlbfs要求用戶和/或系統管理員配置系統內存的哪些部分應該並可以被大頁映射;THP透明地管理這些映射並獲取名稱。
關於 Transparent Hugepage Support
通常,硬體對不同物理內存范圍的訪問方式有所限制。某些情況下,設備不能對所有可定址內存執行DMA。在其他情況下,物理內存的大小超過虛擬內存的最大可定址大小,需要採取特殊措施來訪問部分內存。還有些情況,物理內存的尺寸超過了虛擬內存的最大可定址尺寸,需要採取特殊措施來訪問部分內存。
Linux根據內存頁的使用情況,將其組合為多個 zones 。比如, ZONE_DMA 包含設備用於DMA的內存, ZONE_HIGHMEM 包含未永久映射到內核地址空間的內存, ZONE_NORMAL 包含正常定址內存頁。
內存zones的實際層次架構取決於硬體,因為並非所有架構都定義了所有的zones,不同平台對DMA的要求也不同。
多處理器機器很多基於 NUMA (Non-Uniform Memory Access system - 非統一內存訪問系統 )架構。 在這樣的系統中,根據與處理器的「距離」,內存被安排成具有不同訪問延遲的 banks 。每個 bank 被稱為一個 node ,Linux為每個 node 構造一個獨立的內存管理子系統。 Node 有自己的zones集合、free&used頁面列表,以及各種統計計數器。
What is NUMA?
NUMA Memory Policy
物理內存易失,將數據放入內存的常見情況是讀取文件。讀取文件時,數據會放入 頁面緩存(page cache) ,可以在再次讀取時避免耗時的磁碟訪問。同樣,寫文件時,數據也會被放入 頁面緩存 ,並最終進入存儲設備。被寫入的頁被標記為 臟頁(dirty page) ,當Linux決定將其重用時,它會將更新的數據同步到設備上的文件。
匿名內存 anonymous memory 或 匿名映射 anonymous mappings 表示沒有後置文件系統的內存。這些映射是為程序的stack和heap隱式創建的,或調用mmap(2)顯式創建的。通常,匿名映射只定義允許程序訪問的虛擬內存區域。讀,會創建一個頁表條目,該條目引用一個填充有零的特殊物理頁。寫,則分配一個常規物理頁來保存寫入數據。該頁將被標記為臟頁,如果內核決定重用該頁,則臟頁將被交換出去 swapped out 。
縱貫整個系統生命周期,物理頁可用於存儲不同類型的數據。它可以是內核內部數據結構、設備驅動DMA緩沖區、讀取自文件系統的數據、用戶空間進程分配的內存等。
根據內存頁使用情況,Linux內存管理會區別處理。可以隨時釋放的頁面稱為 可回收(reclaimable) 頁面,因為它們把數據緩存到了其他地方(比如,硬碟),或者被swap out到硬碟上。
可回收頁最值得注意的是 頁面緩存 和 匿名頁面 。
在大多數情況下,存放內部內核數據的頁,和用作DMA緩沖區的頁無法重用,它們將保持現狀直到用戶釋放。這樣的被稱為 不可回收頁(unreclaimable) 。
然而,在特定情況下,即便是內核數據結構佔用的頁面也會被回收。
例如,文件系統元數據的緩存(in-memory)可以從存儲設備中重新讀取,因此,當系統存在內存壓力時,可以從主內存中丟棄它們。
釋放可回收物理內存頁並重新調整其用途的過程稱為 (surprise!) reclaim 。
Linux支持非同步或同步回收頁,取決於系統的狀態。
當系統負載不高時,大部分內存是空閑的,可以立即從空閑頁得到分配。
當系統負載提升後,空閑頁減少,當達到某個閾值( low watermark )時,內存分配請求將喚醒 kswapd 守護進程。它將以非同步的方式掃描內存頁。如果內存頁中的數據在其他地方也有,則釋放這些內存頁;或者退出內存到後置存儲設備(關聯 臟頁 )。
隨著內存使用量進一步增加,並達到另一個閾值- min watermark -將觸發回收。這種情況下,分配將暫停,直到回收到足夠的內存頁。
當系統運行時,任務分配並釋放內存,內存變得碎片化。
雖然使用虛擬內存可以將分散的物理頁表示為虛擬連續范圍,但有時需要分配大的連續的物理內存。這種需求可能會提升。例如,當設備驅動需要一個大的DMA緩沖區時,或當THP分配一個大頁時。
內存地址壓縮(compaction ) 解決了碎片問題。
該機制將佔用的頁從內存zone的下部移動到上部的空閑頁。壓縮掃描完成後,zone開始處的空閑頁就並在一起了,分配較大的連續物理內存就可行了。
與 reclaim 類似, compaction 可以在 kcompactd守護進程中非同步進行,也可以作為內存分配請求的結果同步進行。
在存在負載的機器上,內存可能會耗盡,內核無法回收到足夠的內存以繼續運行。
為了保障系統的其餘部分,引入了 OOM killer 。
OOM killer 選擇犧牲一個任務來保障系統的總體健康。選定的任務被killed,以期望在它退出後釋放足夠的內存以繼續正常的操作。
③ Linux 怎麼獲得分配內存的起始地址
Linux內核運行在X86機器的物理內存管理使用簡單平坦內存模型,每個用戶進程內存(虛擬內存)地址范圍為從0到TASK_SIZE位元組,超過此內存的限制不能被用戶訪問。用戶進程被分為幾個邏輯段,成為虛擬內存區域,內核跟蹤和管理用戶進程的虛擬內存區域提供適當的內存管理和內存保護處理。 do_brk()是一個內核函數,用於間接調用管理進程的內存堆的增加和縮減 (brk),它是一個mmap(2)系統調用的簡化版本,只處理匿名映射(如未初始化數據)。 do_brk()改變進程的地址空間。地址是代表數據段結束的一個指針(事實上是進程的堆區域)。 do_brk()的參數是一個絕對邏輯地址,這個地址代表地址空間新的結尾。更實際地說,我們在編寫用戶程序的時候從來就不應該使用這個函數。使用這個函數的用戶程序就不能再使用malloc(),這是一個大問題,因為標注庫的許多部分依賴於malloc()。 如果在用戶程序中使用do_brk()可能會導致難以發現的程序崩潰。 do_brk(addr, len)函數給從addr到addr+len建立虛擬內存區vm_area_struct(該區的起始地址為addr;結束地址為addr+len),該虛擬內存區作為進程的堆來使用。 malloc將從此區域獲取內存空間(虛擬內存), free()將會把malloc()獲取的虛擬空間釋放掉(歸還到該進程的堆的空閑空間中去)
④ 如何查看Linux內存中的程序所有堆的地址
linux 下面查看內存有多種渠道,比如通過命令 ps ,top,free 等,比如通過/proc系統,一般需要比較詳細和精確地知道整機內存/某個進程內存的使用情況,最好通過/proc 系統,下面介紹/proc系統下內存相關的幾個文件
單個進程的內存查看 cat /proc/[pid] 下面有幾個文件: maps , smaps, status
maps 文件可以查看某個進程的代碼段、棧區、堆區、動態庫、內核區對應的虛擬地址,如果你還不了解linux進程的內存空間,可以參考這里。
下圖是maps文件內存示例
Develop>cat /proc/self/maps
00400000-0040b000 r-xp 00000000 fd:00 48 /mnt/cf/orig/root/bin/cat
0060a000-0060b000 r--p 0000a000 fd:00 48 /mnt/cf/orig/root/bin/cat
0060b000-0060c000 rw-p 0000b000 fd:00 48 /mnt/cf/orig/root/bin/cat 代碼段
0060c000-0062d000 rw-p 00000000 00:00 0 [heap] 堆區
7f1fff43b000-7f1fff5d4000 r-xp 00000000 fd:00 861 /mnt/cf/orig/root/lib64/libc-2.15.so
7f1fff5d4000-7f1fff7d3000 ---p 00199000 fd:00 861 /mnt/cf/orig/root/lib64/libc-2.15.so
7f1fff7d3000-7f1fff7d7000 r--p 00198000 fd:00 861 /mnt/cf/orig/root/lib64/libc-2.15.so
7f1fff7d7000-7f1fff7d9000 rw-p 0019c000 fd:00 861 /mnt/cf/orig/root/lib64/libc-2.15.so
7f1fff7d9000-7f1fff7dd000 rw-p 00000000 00:00 0
7f1fff7dd000-7f1fff7fe000 r-xp 00000000 fd:00 2554 /mnt/cf/orig/root/lib64/ld-2.15.so
7f1fff9f9000-7f1fff9fd000 rw-p 00000000 00:00 0
7f1fff9fd000-7f1fff9fe000 r--p 00020000 fd:00 2554 /mnt/cf/orig/root/lib64/ld-2.15.so
7f1fff9fe000-7f1fff9ff000 rw-p 00021000 fd:00 2554 /mnt/cf/orig/root/lib64/ld-2.15.so
7f1fff9ff000-7f1fffa00000 rw-p 00000000 00:00 0
7fff443de000-7fff443ff000 rw-p 00000000 00:00 0 [stack] 用戶態棧區
7fff443ff000-7fff44400000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] 內核區
有時候可以通過不斷查看某個進程的maps文件,通過查看其虛擬內存(堆區)是否不停增長來簡單判斷進程是否發生了內存溢出。
maps文件只能顯示簡單的分區,smap文件可以顯示每個分區的更詳細的內存佔用數據
下圖是smaps文件內存示例, 實際顯示內容會將每一個區都顯示出來,下面我只拷貝了代碼段和堆區,
每一個區顯示的內容項目是一樣的,smaps文件各項含義可以參考這里
Develop>cat /proc/self/smaps
00400000-0040b000 r-xp 00000000 fd:00 48 /mnt/cf/orig/root/bin/cat
Size: 44 kB 虛擬內存大小
Rss: 28 kB 實際使用物理內存大小
Pss: 28 kB
Shared_Clean: 0 kB 頁面被改,則是dirty,否則是clean,頁面引用計數>1,是shared,否則是private
Shared_Dirty: 0 kB
Private_Clean: 28 kB
Private_Dirty: 0 kB
Referenced: 28 kB
Anonymous: 0 kB
AnonHugePages: 0 kB
Swap: 0 kB 處於交換區的頁面大小
KernelPageSize: 4 kB 操作系統一個頁面大小
MMUPageSize: 4 kB 體系結構MMU一個頁面大小
Locked: 0 kB
0060c000-0062d000 rw-p 00000000 00:00 0 [heap]
Size: 132 kB
Rss: 8 kB
Pss: 8 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 8 kB
Referenced: 8 kB
Anonymous: 8 kB
AnonHugePages: 0 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB
Locked: 0 kB
下圖是status文件內存示例, 加粗部分是內存相關的統計,
Develop>cat /proc/24475/status
Name: netio 可執行程序的名字
State: R (running) 任務狀態,運行/睡眠/僵死
Tgid: 24475 線程組號
Pid: 24475 進程id
PPid: 19635 父進程id
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 256 該進程最大文件描述符個數
Groups: 0
VmPeak: 6330708 kB 內存使用峰值
VmSize: 268876 kB 進程虛擬地址空間大小
VmLck: 0 kB 進程鎖住的物理內存大小,鎖住的物理內存無法交換到硬碟
VmHWM: 16656 kB
VmRSS: 11420 kB 進程正在使用的物理內存大小
VmData: 230844 kB 進程數據段大小
VmStk: 136 kB 進程用戶態棧大小
VmExe: 760 kB 進程代碼段大小
VmLib: 7772 kB 進程使用的庫映射到虛擬內存空間的大小
VmPTE: 120 kB 進程頁表大小
VmSwap: 0 kB
Threads: 5
SigQ: 0/63346
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000001000000
SigCgt: 0000000180000000
CapInh: 0000000000000000
CapPrm: ffffffffffffffff
CapEff: ffffffffffffffff
CapBnd: ffffffffffffffff
Cpus_allowed: 01
Cpus_allowed_list: 0
Mems_allowed: 01
Mems_allowed_list: 0
voluntary_ctxt_switches: 201
nonvoluntary_ctxt_switches: 909
可以看到,linux下內存佔用是一個比較復雜的概念,不能
簡單通過一個單一指標就判斷某個程序「內存消耗」大小,原因有下面2點:
進程所申請的內存不一定真正會被用到(malloc或mmap的實現)
真正用到了的內存也不一定是只有該進程自己在用 (比如動態共享庫)
關於內存的使用分析及本文幾個命令的說明也可以參考這里
下面是查看整機內存使用情況的文件 /proc/meminfo
Develop>cat /proc/meminfo
MemTotal: 8112280 kB 所有可用RAM大小 (即物理內存減去一些預留位和內核的二進制代碼大小)
MemFree: 4188636 kB LowFree與HighFree的總和,被系統留著未使用的內存
Buffers: 34728 kB 用來給文件做緩沖大小
Cached: 289740 kB 被高速緩沖存儲器(cache memory)用的內存的大小
(等於 diskcache minus SwapCache )
SwapCached: 0 kB 被高速緩沖存儲器(cache memory)用的交換空間的大小
已經被交換出來的內存,但仍然被存放在swapfile中。
用來在需要的時候很快的被替換而不需要再次打開I/O埠
Active: 435240 kB 在活躍使用中的緩沖或高速緩沖存儲器頁面文件的大小,
除非非常必要否則不會被移作他用
Inactive: 231512 kB 在不經常使用中的緩沖或高速緩沖存儲器頁面文件的大小,可能被用於其他途徑.
Active(anon): 361252 kB
Inactive(anon): 120688 kB
Active(file): 73988 kB
Inactive(file): 110824 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 0 kB 交換空間的總大小
SwapFree: 0 kB 未被使用交換空間的大小
Dirty: 0 kB 等待被寫回到磁碟的內存大小
Writeback: 0 kB 正在被寫回到磁碟的內存大小
AnonPages: 348408 kB 未映射頁的內存大小
Mapped: 33600 kB 已經被設備和文件等映射的大小
Shmem: 133536 kB
Slab: 55984 kB 內核數據結構緩存的大小,可以減少申請和釋放內存帶來的消耗
SReclaimable: 25028 kB 可收回Slab的大小
SUnreclaim: 30956 kB 不可收回Slab的大小(SUnreclaim+SReclaimable=Slab)
KernelStack: 1896 kB 內核棧區大小
PageTables: 8156 kB 管理內存分頁頁面的索引表的大小
NFS_Unstable: 0 kB 不穩定頁表的大小
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 2483276 kB
Committed_AS: 1804104 kB
VmallocTotal: 34359738367 kB 可以vmalloc虛擬內存大小
VmallocUsed: 565680 kB 已經被使用的虛擬內存大小
VmallocChunk: 34359162876 kB
HardwareCorrupted: 0 kB
HugePages_Total: 1536 大頁面數目
HugePages_Free: 0 空閑大頁面數目
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB 大頁面一頁大小
DirectMap4k: 10240 kB
DirectMap2M: 8302592 kB
⑤ 內存管理:一文讀懂Linux內存組織結構及頁面布局
1、內存是什麼?
1) 內存又稱主存,是 CPU 能直接定址的存儲森鄭空間,由半導體器件製成;
2) 內存的特點是存取速率快,斷電一般不保存數據,非持久化設備;
2、內存的作用
1) 暫時存放 cpu 的運算數據
2) 硬碟等外部存儲器交換的數據
3) 保障 cpu 計算機的穩定性和高性能
1、linux 內存地址空間 Linux 內存管理全貌
2、內存地址——用戶態&內核態
3、內存地址——MMU 地址轉換
4、內存地址——分段機制
1) 段選擇符
更多Linux內核視頻教程文檔資料免費領取後台私信【 內核 】自行獲取。
內核學習網站:
Linux內核源碼/內存調優/文件系統/進程管理/設備驅動/網路協議棧-學習視頻教程-騰訊課堂
2) 分段實現
5、內存地址——分頁機制(32 位)
6、用戶態地址空間
7、內核態地址空間
8、進程內存空間
內存管理演算法 ——對討厭自己管理內存的人來說是天賜的禮物
1、內存碎片
1) 基本原理
2) 如何避免內存碎片
2、夥伴系統演算法——組織結構
1) 概念
2) 外部碎片
3、夥伴系統演算法——申請和回收
1) 申請演算法
2) 回收演算法
3) 條件
4、如何分配 4M 以上內存?
1) 為何限制大旦春盯塊內存分配
2) 內核中獲取 4M 以上大內存的方法
5、夥伴系統——反碎片機制
1) 不可移動頁
2) 可回收頁
6、slab 演算法——基本原理
1) 基本概念
2) 內部碎片
7、slab 分配器的結構
詳細參考:
經典|圖解Linux內存性能優化核心思想
8、slab 高速緩存
1) 普通高速緩存
2) 專用高速緩存
9、內核態內存池
1) 基本原理
2) 內核 API
10、用戶態內存池
1) C++ 實例
11、DMA 內存
1) 什麼是 DMA
2) DMA 信號
out of memory 的時代過去了嗎?no,內存再充足也不可任性使用。
1、內存的使用場景
2、用戶態內存分配函數
a) 如果當前連續內存塊足夠 realloc 的話,只是將 p 所指向的空間擴大,並返回模和 p 的指針地址。這個時候 q 和 p 指向的地址是一樣的
b) 如果當前連續內存塊不夠長度,再找一個足夠長的地方,分配一塊新的內存,q,並將 p 指向的內容 到 q,返回 q。並將 p 所指向的內存空間刪除
3、內核態內存分配函數
4、malloc 申請內存
5、缺頁異常
6、用戶進程訪問內存分析
7、共享內存
1) 原理
2) shm 介面
1、C 內存泄露
2、C 野指針
3、C 資源訪問沖突
4、STL 迭代器失效
錯誤示例:刪除當前迭代器,迭代器會失效
正確示例:迭代器 erase 時,需保存下一個迭代器
5、C++ 11 智能指針
(1)原理分析:
(2)數據結構:
(3)使用方法:
6、C++ 11 更小更快更安全
六、 如何查看內存
可以通過 cat /proc/slabinfo 命令查看
可以通過 /proc/sys/vm/drop_caches來釋放