時間:2015/6/28來源:IT貓撲網(wǎng)作者:網(wǎng)管聯(lián)盟我要評論(0)
這周BSP那邊碰到一個蠻嚴重的issue:
循環(huán)放電影,v4l2 output driver的 dma_alloc很容易就失敗,kernel panic,dump出當前buddy系統(tǒng)的狀態(tài)。
初步分析是由于內存fragment導致沒有足夠大的連續(xù)內存分配給v4l output driver。開始debug
首先通過/proc/buddyinfo 在播放電影時候不間斷的dump buddy狀態(tài),發(fā)現(xiàn)大塊內存塊:256K - 4MB block
減少的很迅速,1-2小時后,buddy中就不存在大塊連續(xù)內存。這證明了初步分析是正確的,但是還不知道是誰導致了fragment,是應用層,還是v4l2 driver本身?
接下來添加一個NORMAL zone(arm體系中就DMA一個zone,所以application和dma都使用一個buddy系統(tǒng)),讓普通內存分配和dma隔開。繼續(xù)測試,發(fā)現(xiàn)dma zone中的內存塊狀態(tài)在最初很正常,但NORMAL zone的內存卻在急劇減少,最終NORMAL zone已經(jīng)沒有足夠內存給application,kernel轉而向DMA zone申請,最終issue重現(xiàn)。
現(xiàn)在問題很清楚了,application發(fā)生內存leak,很嚴重的leak。但是dma_alloc這邊會沒有問題馬?
Fred在看了我描述的問題后,指出了dma_alloc中算法的一些問題:當向buddy申請完足夠size的2^的內存塊后,
該函數(shù)會釋放在申請塊中多余的page,加速了fragment。后來我們做了一個實驗,將dma_alloc里的釋放多余頁的功能去掉,fragment的速度大大減緩。
經(jīng)過上周對這個issue的研究,我開始重新總結kernel里對內存分配的方式和方法,總結如下:
頁分配
unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
直接從buddy系統(tǒng)中獲得原始頁。最原始的分配方式。
slab分配器
1. 通用 cache
void *kmalloc(size_t size, gfp_t flags)
kmalloc 基于以下幾種size的mem cache:32, 64, 128, 256, 512, 1,024, 2,048, 4,096,
8,192, 16,384, 32,768, 65,536 和 131,072 bytes。其本質也是調用kmem_cache_alloc來分配
object。所以kmalloc一次最大可分配的size為128KB。kmalloc分配速度很快,在分配時需注意gfp flag
參數(shù):在不interrupt上下文(ISR, softirq, tasklet)及不可睡眠上下文使用GFP_ATOMIC。
內核還增加了內存清零的分配函數(shù):kzalloc。
2. 專用 cache
kmem_cache_create()
void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
如果你需要頻繁的分配和釋放某個結構,建議不要采用kmalloc,而是自己在slab系統(tǒng)中創(chuàng)建memory cache。
指定該結構的object size。分配時使用kmem_cache_alloc。同樣的slab object大小也有限制,一般情況下一個MAX_OBJ_ORDER是5,也就是32個頁,128KB。
非連續(xù)內存分配
void *vmalloc(unsigned long size)
超過128KB的內存顯然不能使用slab分配,并且當申請的連續(xù)內存大小不能在buddy系統(tǒng)中得到滿足,那么就需要使用vmalloc。vmalloc為了把物理的非連續(xù)頁一個個映射,從而導致比直接內存映射大的多的后援緩沖區(qū)抖動。除非需要特別大的內存,否則盡量不要使用vmalloc。
基于DMA 分配
void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
在某些arch中,可以使用dma_alloc_coherent來分配DMA專用內存。列入在arch/arm/mm/consistent.c中,該函數(shù)先分配最小可滿足size的2^order內存,然后釋放2^order-size多余的頁給buddy。而arch/i386/
kernel/pci-dma.c中,則直接分配2^order塊內存。
直接映射分配
ioremap(unsigned long phys_addr, size_t size)
int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t prot)
在某些體系結構中,我們可以保留memory map段上的某一個區(qū)域,作為dma或其他設備的專有內存。
這段內存并不在kernel buddy的控制之下(沒有被放入mem_maps),你也無法從以上幾種分配方式中得到這些內存。這個時候,你可以用ioremap和remap_pfn_range將這段內存直接映射到vm上。
關鍵詞標簽:Linux,Kernel內存
相關閱讀
熱門文章 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程使用screen管理你的遠程會話GNU/Linux安裝vmware如何登錄linux vps圖形界面 Linux遠程桌面連
人氣排行 Linux下獲取CPUID、硬盤序列號與MAC地址linux tc實現(xiàn)ip流量限制dmidecode命令查看內存型號linux下解壓rar文件安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程Ubuntu linux 關機、重啟、注銷 命令lcx.exe、nc.exe、sc.exe入侵中的使用方法查看linux服務器硬盤IO讀寫負載