Linux内存技术分析(下)
Linux內(nèi)存技術分析(下)
五、 內(nèi)存使用場景
out of memory 的時代過去了嗎?no,內(nèi)存再充足也不可任性使用。
1、內(nèi)存的使用場景
· page管理
· slab(kmalloc、內(nèi)存池)
· 用戶態(tài)內(nèi)存使用(malloc、relloc 文件映射、共享內(nèi)存)
· 程序的內(nèi)存 map(棧、堆、code、data)
· 內(nèi)核和用戶態(tài)的數(shù)據(jù)傳遞(copy_from_user、copy_to_user)
· 內(nèi)存映射(硬件寄存器、保留內(nèi)存)
· DMA 內(nèi)存
2、用戶態(tài)內(nèi)存分配函數(shù)
· alloca是向棧申請內(nèi)存,因此無需釋放
· malloc所分配的內(nèi)存空間未被初始化,使用 malloc() 函數(shù)的程序開始時(內(nèi)存空間還沒有被重新分配) 能正常運行,但經(jīng)過一段時間后(內(nèi)存空間已被重新分配) 可能會出現(xiàn)問題
· calloc會將所分配的內(nèi)存空間中的每一位都初始化為零
· realloc擴展現(xiàn)有內(nèi)存空間大小
· a) 如果當前連續(xù)內(nèi)存塊足夠realloc 的話,只是將 p所指向的空間擴大,并返回 p的指針地址。這個時候 q和 p指向的地址是一樣的
· b) 如果當前連續(xù)內(nèi)存塊不夠長度,再找一個足夠長的地方,分配一塊新的內(nèi)存,q,并將 p指向的內(nèi)容copy 到 q,返回 q。并將 p所指向的內(nèi)存空間刪除
3、內(nèi)核態(tài)內(nèi)存分配函數(shù)
函數(shù)分配原理最大內(nèi)存其他_get_free_pages直接對頁框進行操作4MB適用于分配較大量的連續(xù)物理內(nèi)存kmem_cache_alloc基于 slab 機制實現(xiàn)128KB適合需要頻繁申請釋放相同大小內(nèi)存塊時使用kmalloc基于 kmem_cache_alloc 實現(xiàn)128KB最常見的分配方式,需要小于頁框大小的內(nèi)存時可以使用vmalloc建立非連續(xù)物理內(nèi)存到虛擬地址的映射物理不連續(xù),適合需要大內(nèi)存,但是對地址連續(xù)性沒有要求的場合dma_alloc_coherent基于_alloc_pages 實現(xiàn)4MB適用于 DMA 操作ioremap實現(xiàn)已知物理地址到虛擬地址的映射適用于物理地址已知的場合,如設備驅動alloc_bootmem在啟動 kernel 時,預留一段內(nèi)存,內(nèi)核看不見小于物理內(nèi)存大小,內(nèi)存管理要求較高
4、malloc 申請內(nèi)存
· 調用malloc 函數(shù)時,它沿 free_chuck_list 連接表尋找一個大到足以滿足用戶請求所需要的內(nèi)存塊
· free_chuck_list連接表的主要工作是維護一個空閑的堆空間緩沖區(qū)鏈表
· 如果空間緩沖區(qū)鏈表沒有找到對應的節(jié)點,需要通過系統(tǒng)調用 sys_brk 延伸進程的棧空間
5、缺頁異常
· 通過get_free_pages 申請一個或多個物理頁面
· 換算addr 在進程 pdg 映射中所在的 pte 地址
· 將addr 對應的 pte 設置為物理頁面的首地址
· 系統(tǒng)調用:Brk—申請內(nèi)存小于等于 128kb,do_map—申請內(nèi)存大于 128kb
6、用戶進程訪問內(nèi)存分析
· 用戶態(tài)進程獨占虛擬地址空間,兩個進程的虛擬地址可相同
· 在訪問用戶態(tài)虛擬地址空間時,如果沒有映射物理地址,通過系統(tǒng)調用發(fā)出缺頁異常
· 缺頁異常陷入內(nèi)核,分配物理地址空間,與用戶態(tài)虛擬地址建立映射
7、共享內(nèi)存
- 原理
· 它允許多個不相關的進程去訪問同一部分邏輯內(nèi)存
· 兩個運行中的進程之間傳輸數(shù)據(jù),共享內(nèi)存將是一種效率極高的解決方案
· 兩個運行中的進程共享數(shù)據(jù),是進程間通信的高效方法,可有效減少數(shù)據(jù)拷貝的次數(shù)
2) Shm 接口
· shmget創(chuàng)建共享內(nèi)存
· shmat啟動對該共享內(nèi)存的訪問,并把共享內(nèi)存連接到當前進程的地址空間
· shmdt將共享內(nèi)存從當前進程中分離
六、 內(nèi)存使用那些坑
1、C 內(nèi)存泄露
· 在類的構造函數(shù)和析構函數(shù)中沒有匹配地調用 new 和 delete 函數(shù)
· 沒有正確地清除嵌套的對象指針
· 沒有將基類的析構函數(shù)定義為虛函數(shù)
· 當基類的指針指向子類對象時,如果基類的析構函數(shù)不是 virtual,那么子類的析構函數(shù)將不會被調用,子類的資源沒有得到正確釋放,因此造成內(nèi)存泄露
· 缺少拷貝構造函數(shù),按值傳遞會調用(拷貝)構造函數(shù),引用傳遞不會調用
· 指向對象的指針數(shù)組不等同于對象數(shù)組,數(shù)組中存放的是指向對象的指針,不僅要釋放每個對象的空間,還要釋放每個指針的空間
· 缺少重載賦值運算符,也是逐個成員拷貝的方式復制對象,如果這個類的大小是可變的,那么結果就是造成內(nèi)存泄露
2、C 野指針
· 指針變量沒有初始化
· 指針被 free 或 delete 后,沒有設置為 NULL
· 指針操作超越了變量的作用范圍,比如返回指向棧內(nèi)存的指針就是野指針
· 訪問空指針(需要做空判斷)
· sizeof無法獲取數(shù)組的大小
· 試圖修改常量,如:char p=“1234”;p=‘1’;
3、C 資源訪問沖突
· 多線程共享變量沒有用 valotile 修飾
· 多線程訪問全局變量未加鎖
· 全局變量僅對單進程有效
· 多進程寫共享內(nèi)存數(shù)據(jù),未做同步處理
· mmap內(nèi)存映射,多進程不安全
4、STL 迭代器失效
· 被刪除的迭代器失效
· 添加元素(insert/push_back 等)、刪除元素導致順序容器迭代器失效
錯誤示例:刪除當前迭代器,迭代器會失效
正確示例:迭代器 erase 時,需保存下一個迭代器
5、C++ 11 智能指針
· auto_ptr替換為 unique_ptr
· 使用make_shared 初始化一個 shared_ptr
· weak_ptr智能指針助手(1)原理分析:
(2)數(shù)據(jù)結構:
(3)使用方法:a.
lock() 獲取所管理的對象的強引用指針 b. expired() 檢測所管理的對象是否已經(jīng)釋放 c. get() 訪問智能指針對象
6、C++ 11 更小更快更安全
· std::atomic原子數(shù)據(jù)類型 多線程安全
· std::array定長數(shù)組開銷比 array 小和 std::vector 不同的是 array 的長度是固定的,不能動態(tài)拓展
· std::vectorvector 瘦身 shrink_to_fit():將 capacity 減少為于 size() 相同的大小
· td::forward_list forward_list 是單鏈表(std::list 是雙鏈表),只需要順序遍歷的場合,forward_list 能更加節(jié)省內(nèi)存,插入和刪除的性能高于 list
· std::unordered_map、std::unordered_set用 hash 實現(xiàn)的無序的容器,插入、刪除和查找的時間復雜度都是 O(1),在不關注容器內(nèi)元素順序的場合,使用 unordered 的容器能獲得更高的性能六、 如何查看內(nèi)存
· 系統(tǒng)中內(nèi)存使用情況:/proc/meminfo
· 進程的內(nèi)存使用情況:/proc/28040/status
· 查詢內(nèi)存總使用率:free
· 查詢進程 cpu 和內(nèi)存使用占比:top
· 虛擬內(nèi)存統(tǒng)計:vmstat
· 進程消耗內(nèi)存占比和排序:ps aux –sort -rss
· 釋放系統(tǒng)內(nèi)存緩存:
/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
總結
以上是生活随笔為你收集整理的Linux内存技术分析(下)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux内存技术分析(上)
- 下一篇: 高精地图与自动驾驶(上)