Linux內存技術分析(下)

Linux內存技術分析(下)

五、 內存使用場景

out of memory 的時代過去了嗎?no,內存再充足也不可任性使用。

1、內存的使用場景

· page管理

· slab(kmalloc、內存池)

· 用戶態內存使用(malloc、relloc 文件映射、共享內存)

· 程序的內存 map(棧、堆、code、data)

· 內核和用戶態的數據傳遞(copy_from_user、copy_to_user)

· 內存映射(硬件寄存器、保留內存)

· DMA 內存

2、用戶態內存分配函數

· alloca是向棧申請內存,因此無需釋放

· malloc所分配的內存空間未被初始化,使用 malloc() 函數的程序開始時(內存空間還沒有被重新分配) 能正常運行,但經過一段時間後(內存空間已被重新分配) 可能會出現問題

· calloc會將所分配的內存空間中的每一位都初始化爲零

· realloc擴展現有內存空間大小

· a) 如果當前連續內存塊足夠realloc 的話,只是將 p所指向的空間擴大,並返回 p的指針地址。這個時候 q和 p指向的地址是一樣的

· b) 如果當前連續內存塊不夠長度,再找一個足夠長的地方,分配一塊新的內存,q,並將 p指向的內容copy 到 q,返回 q。並將 p所指向的內存空間刪除

3、內核態內存分配函數

函數分配原理最大內存其他_get_free_pages直接對頁框進行操作4MB適用於分配較大量的連續物理內存kmem_cache_alloc基於 slab 機制實現128KB適合需要頻繁申請釋放相同大小內存塊時使用kmalloc基於 kmem_cache_alloc 實現128KB最常見的分配方式,需要小於頁框大小的內存時可以使用vmalloc建立非連續物理內存到虛擬地址的映射物理不連續,適合需要大內存,但是對地址連續性沒有要求的場合dma_alloc_coherent基於_alloc_pages 實現4MB適用於 DMA 操作ioremap實現已知物理地址到虛擬地址的映射適用於物理地址已知的場合,如設備驅動alloc_bootmem在啓動 kernel 時,預留一段內存,內核看不見小於物理內存大小,內存管理要求較高
4、malloc 申請內存

· 調用malloc 函數時,它沿 free_chuck_list 連接表尋找一個大到足以滿足用戶請求所需要的內存塊
在這裏插入圖片描述
· free_chuck_list連接表的主要工作是維護一個空閒的堆空間緩衝區鏈表

· 如果空間緩衝區鏈表沒有找到對應的節點,需要通過系統調用 sys_brk 延伸進程的棧空間
在這裏插入圖片描述
5、缺頁異常

· 通過get_free_pages 申請一個或多個物理頁面

· 換算addr 在進程 pdg 映射中所在的 pte 地址

· 將addr 對應的 pte 設置爲物理頁面的首地址

· 系統調用:Brk—申請內存小於等於 128kb,do_map—申請內存大於 128kb
在這裏插入圖片描述
6、用戶進程訪問內存分析

· 用戶態進程獨佔虛擬地址空間,兩個進程的虛擬地址可相同

· 在訪問用戶態虛擬地址空間時,如果沒有映射物理地址,通過系統調用發出缺頁異常

· 缺頁異常陷入內核,分配物理地址空間,與用戶態虛擬地址建立映射
在這裏插入圖片描述
7、共享內存

  1. 原理

· 它允許多個不相關的進程去訪問同一部分邏輯內存

· 兩個運行中的進程之間傳輸數據,共享內存將是一種效率極高的解決方案

· 兩個運行中的進程共享數據,是進程間通信的高效方法,可有效減少數據拷貝的次數
在這裏插入圖片描述
2) Shm 接口

· shmget創建共享內存

· shmat啓動對該共享內存的訪問,並把共享內存連接到當前進程的地址空間

· shmdt將共享內存從當前進程中分離

六、 內存使用那些坑

1、C 內存泄露

· 在類的構造函數和析構函數中沒有匹配地調用 new 和 delete 函數
在這裏插入圖片描述
· 沒有正確地清除嵌套的對象指針

· 沒有將基類的析構函數定義爲虛函數

· 當基類的指針指向子類對象時,如果基類的析構函數不是 virtual,那麼子類的析構函數將不會被調用,子類的資源沒有得到正確釋放,因此造成內存泄露

· 缺少拷貝構造函數,按值傳遞會調用(拷貝)構造函數,引用傳遞不會調用

· 指向對象的指針數組不等同於對象數組,數組中存放的是指向對象的指針,不僅要釋放每個對象的空間,還要釋放每個指針的空間

· 缺少重載賦值運算符,也是逐個成員拷貝的方式複製對象,如果這個類的大小是可變的,那麼結果就是造成內存泄露

2、C 野指針

· 指針變量沒有初始化

· 指針被 free 或 delete 後,沒有設置爲 NULL

· 指針操作超越了變量的作用範圍,比如返回指向棧內存的指針就是野指針

· 訪問空指針(需要做空判斷)

· sizeof無法獲取數組的大小

· 試圖修改常量,如:char p=“1234”;p=‘1’;

3、C 資源訪問衝突

· 多線程共享變量沒有用 valotile 修飾

· 多線程訪問全局變量未加鎖

· 全局變量僅對單進程有效

· 多進程寫共享內存數據,未做同步處理

· mmap內存映射,多進程不安全

4、STL 迭代器失效

· 被刪除的迭代器失效

· 添加元素(insert/push_back 等)、刪除元素導致順序容器迭代器失效

錯誤示例:刪除當前迭代器,迭代器會失效
在這裏插入圖片描述
正確示例:迭代器 erase 時,需保存下一個迭代器
在這裏插入圖片描述
5、C++ 11 智能指針

· auto_ptr替換爲 unique_ptr
在這裏插入圖片描述
· 使用make_shared 初始化一個 shared_ptr
在這裏插入圖片描述
· weak_ptr智能指針助手(1)原理分析:
在這裏插入圖片描述
(2)數據結構:
在這裏插入圖片描述
(3)使用方法:a.
lock() 獲取所管理的對象的強引用指針 b. expired() 檢測所管理的對象是否已經釋放 c. get() 訪問智能指針對象

6、C++ 11 更小更快更安全

· std::atomic原子數據類型 多線程安全

· std::array定長數組開銷比 array 小和 std::vector 不同的是 array 的長度是固定的,不能動態拓展

· std::vectorvector 瘦身 shrink_to_fit():將 capacity 減少爲於 size() 相同的大小

· td::forward_list forward_list 是單鏈表(std::list 是雙鏈表),只需要順序遍歷的場合,forward_list 能更加節省內存,插入和刪除的性能高於 list

· std::unordered_map、std::unordered_set用 hash 實現的無序的容器,插入、刪除和查找的時間複雜度都是 O(1),在不關注容器內元素順序的場合,使用 unordered 的容器能獲得更高的性能六、 如何查看內存

· 系統中內存使用情況:/proc/meminfo
在這裏插入圖片描述
· 進程的內存使用情況:/proc/28040/status

· 查詢內存總使用率:free
在這裏插入圖片描述
· 查詢進程 cpu 和內存使用佔比:top
在這裏插入圖片描述
· 虛擬內存統計:vmstat
在這裏插入圖片描述
· 進程消耗內存佔比和排序:ps aux –sort -rss
在這裏插入圖片描述
· 釋放系統內存緩存:

/proc/sys/vm/drop_caches

· To free pagecache, use echo 1 > /proc/sys/vm/drop_caches

· To free dentries and inodes, use echo 2 > /proc/sys/vm/drop_caches

· To free pagecache, dentries and inodes, use echo 3 >/proc/sys/vm/drop_caches

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章