娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

IMX257 Linux內存空間內存分配

發布者:溫暖的微風最新更新時間:2024-08-15 來源: cnblogs關鍵字:Linux  內存空間  內存分配 手機看文章 掃描二維碼
隨時隨地手機看文章

一、KMALLOC

kmalloc 是一個功能強大且高速(除非被阻塞)的工具,所分配到的內存在物理內存中連續且保持原有的數據(不清零)。原型:

#include

void *kmalloc(size_t size, int flags);

參數詳解:

size 參數

 

內核管理系統的物理內存,物理內存只能按頁面進行分配。kmalloc 和典型的用戶空間 malloc 在實際上有很大的差別,內核使用特殊的基于頁的分配技術,以最佳的方式利用系統 RAM。Linux 處理內存分配的方法:創建一系列內存對象集合,每個集合內的內存塊大小是固定。處理分配請求時,就直接在包含有足夠大內存塊的集合中傳遞一個整塊給請求 者。

 

必須注意的是:內核只能分配一些預定義的、固定大小的字節數組。kmalloc 能夠處理的最小內存塊是 32 或 64 字節(體系結構依賴),而內存塊大小的上限隨著體系和內核配置而變化。考慮到移植性,不應分配大于 128 KB的內存。若需多于幾個 KB的內存塊,最好使用其他方法。

 

flags 參數

 

內存分配最終總是調用 __get_free_pages 來進行實際的分配,這就是 GFP_ 前綴的由來。

所有標志都定義在 ,有符號代表常常使用的標志組合。

主要的標志常被稱為分配優先級,包括:

 

GFP_KERNEL

最常用的標志,意思是這個分配代表運行在內核空間的進程進行。內核正常分配內存。當空閑內存較少時,可能進入休眠來等待一個頁面。當前進程休眠時, 內核會采取適當的動作來獲取空閑頁。所以使用 GFP_KERNEL 來分配內存的函數必須是可重入,且不能在原子上下文中運行。

 

GFP_ATOMIC

內核通常會為原子性的分配預留一些空閑頁。當當前進程不能被置為睡眠時,應使用 GFP_ATOMIC,這樣kmalloc 甚至能夠使用最后一個空閑頁。如果連這最后一個空閑頁也不存在,則分配返回失敗。常用來從中斷處理和進程上下文之外的其他代碼中分配內存,從不睡眠。

 

GFP_USER

用來為用戶空間分配內存頁,可能睡眠。

 

GFP_HIGHUSER

類似 GFP_USER,如果有高端內存,就從高端內存分配。

 

GFP_NOIO

 

GFP_NOFS

功能類似 GFP_KERNEL,但是為內核分配內存的工作增加了限制。具有GFP_NOFS 的分配不允許執行任何文件系統調用,而 GFP_NOIO 禁止任何 I/O 初始化。它們主要用在文件系統和虛擬內存代碼。那里允許分配休眠,但不應發生遞歸的文件系統調。

Linux 內核把內存分為 3 個區段: 可用于DMA的內存(位于一個特別的地址范圍的內存, 外設可以在這里進行 DMA 存取)、常規內存和高端內存(為了訪問(相對)大量的內存而存在的一種機制)。目的是使每中計算機平臺都必須知道如何將自己特定的內存范圍歸類到這三個區 段中,而不是所有RAM都一樣。

 

當要分配一個滿足kmalloc要求的新頁時, 內核會建立一個內存區段的列表以供搜索。若指定了 __GFP_DMA, 只有可用于DMA的內存區段被搜索;若沒有指定特別的標志, 常規和 可用于DMA的內存區段都被搜索; 若 設置了 __GFP_HIGHMEM,所有的 3 個區段都被搜索(注意:kmalloc 不能分配高端內存)。

 

內存區段背后的機制在 mm/page_alloc.c 中實現, 且區段的初始化時平臺相關的, 通常在 arch 目錄樹的 mm/init.c中。

 

有的標志用雙下劃線做前綴,他們可與上面標志'或'起來使用,以控制分配方式:

 

__GFP_DMA

要求分配可用于DMA的內存。

 

__GFP_HIGHMEM

分配的內存可以位于高端內存.

 

__GFP_COLD

通常,分配器試圖返回'緩存熱(cache warm)'頁面(可在處理器緩存中找到的頁面)。 而這個標志請求一個尚未使用的'冷'頁面。對于用作 DMA 讀取的頁面分配,可使用此標志。因為此時頁面在處理器緩存中沒多大幫助。

 

__GFP_NOWARN

當一個分配無法滿足,阻止內核發出警告(使用 printk )。

 

__GFP_HIGH

高優先級請求,允許為緊急狀況消耗被內核保留的最后一些內存頁。

 

__GFP_REPEAT

 

__GFP_NOFAIL

 

__GFP_NORETRY

告訴分配器當滿足一個分配有困難時,如何動作。__GFP_REPEAT 表示努力再嘗試一次,仍然可能失敗; __GFP_NOFAIL 告訴分配器盡最大努力來滿足要求,始終不返回失敗,不推薦使用; __GFP_NORETRY 告知分配器如果無法滿足請求,立即返回。

前面知識點摘自: http://www.douban.com/note/56607778/

 

二、后備高速緩存 (lookaside cache)

內核中普通對象進行初始化所需的時間超過了對其進行分配和釋放所需的時間,因此不應該將內存釋放回一個全局的內存池,而是將內存保持為針對特定目而初始化的狀態。例如,如果內存被分配給了一個互斥鎖,那么只需在為互斥鎖首次分配內存時執行一次互斥鎖初始化函數(mutex_init)即可。后續的內存分配不需要執行這個初始化函數,因為從上次釋放和調用析構之后,它已經處于所需的狀態中了。

linux2.6中USB和SCSI驅動程序使用了這種高速緩存,是為一些反復使用的塊增加某些特殊的內存池。后背高速緩存管理也叫slab分配器,相關函數和類型在中申明。

slab分配器實現高速緩存具有kmem_cache_t類型。

kmem_cache_t * kmem_cache_create( const char *name, size_t size, size_t align,

unsigned long flags;

void (*constructor)(void*, kmem_cache_t *, unsigned long),

void (*destructor)(void*, kmem_cache_t *, unsigned long));

 

用于創建一個新的高速緩存對象。

constructor用于初始化新分配的對象,destructor用于清除對象。

一旦某個對象的高速緩存被創建以后,就可以調用kmem_cache_alloc從中分配內存對象。

void * kmem_cache_alloc(kmem_cache_t *cache,int flags);

釋放內存對象使用kmem_cache_free

void kmem_cache_free(kmem_cache_t *cache,const void *obj);

在內存空間都被釋放后,模塊被卸載前,驅動程序應當釋放他的高速緩存。

int kmem_cache_destory(kmem_cache_t *cache);

要檢查其返回狀態,如果失敗,表明莫塊中發生了內存泄露。

基于slab的高速緩存scullc

kmem_cache_t *scullc_cache;

scullc_cache=kmem_cache_creat('scullc',scullc_quantum,0,SLAB_HWCACHE_ALIGN,NULL,NULL);

if(!scullc_cache)

{

scullc_cleanup();

return -ENOMEM;

}

if(!dpte->data[s_pos])

{

dptr->data[s_pos]=kmem_cache_alloc(scullc_cache,GFP_KERNEL);

if(!dptr->data[s_pos])

goto nomem;

memset(dptr->data[s_pos],0,scullc_quantum);

}

for(i=0;i{

if(dptr->data[i])

kmem_cache_free(scullc_cache,dptr->data[i]);

}

if(scullc_cache)

kmem_cache_destory(scullc_cache);

 

三、內存池

內核中有些地方的內存分配是不允許失敗的,為確保能分配成功,內核建立一種稱為內存池的抽象,他試圖始終保持空閑狀態,以便緊急情況使用。

mempool_t * mempool_creat(int min_nr,

mempool_alloc_t *alloc_fn, //對象分分配 mempool_alloc_slab

mempool_free_t *free_fn, //釋放 mempool_free_slab

void *pool_data);

 

可以用如下代碼來構造內存池

cache=kmem_cache_creat(...); //創建一個高速緩存

pool=mempool_creat(MY_POOL_MINIMUM,mempool_alloc_slab,mempool_free_slab,cache);//建立內存池對象

void *mempool_alloc(mempool_t *poll,int gfp_mask);//分配對象

void *mempool_free(void *element,mempool_t *poll);//釋放對象

void mempool_destroy(mempool_t *poll);//銷毀內存池

 

注意:mempool會分配一些內存塊,空閑且不會被用到,造成內存的大量浪費。所以一般情況不要用內存池。

 

四、實例分析

1.定義內存操作的指針

2.在init函數中,分別使用kmalloc,get_zeroed_page,vmalloc申請物理內存,整頁內存,虛擬內存

 

3.申請內存之后就是讀寫內存

 

4.當我們不用內存時,在exit函數中釋放內存,防止造成內存泄露

 

5.編譯測試

 

如圖所示,當我們insmod時,打印出了申請的內存的地址,并且成功的讀出了我們寫入的數據

附上驅動代碼:


  1 /*在內存中申請1k 大小的內存做為簡單的一個設備來訪問*/

  2 #include

  3 #include

  4 #include

  5 #include

  6 #include

  7 #include

  8 #include

  9 #include

 10 #include

 11 #include

 12 #include

 13 #include

 14 #include

 15 

 16 #define Driver_NAME 'kmalloc'

 17 #define DEVICE_NAME 'kmalloc'

 18 

 19 static int major = 0;

 20 

 21 //auto to create device node

 22 static struct class *drv_class = NULL;

 23 static struct class_device *drv_class_dev = NULL;

 24 

 25 //定義內存分配的指針

 26 char *buf1 = NULL;

 27 char *buf2 = NULL;

 28 char *buf3 = NULL;

 29 

 30 static int key_open(struct inode *inode, struct file *file)

 31 {

 32     printk('<0>function open!nn');

 33     return 0;

 34 }

 35 

 36 static int key_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)

 37 {

 38     return 0;

 39 }

 40 

 41 static ssize_t key_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)

 42 {

 43     printk('<0>function write!nn');

 44     return 1;

 45 }

 46 

 47 static int  key_release(struct inode *inode, struct file *filp)

 48 {

 49     printk('<0>function write!nn');

 50     return 0;

 51 }

 52 

 53 static int key_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg)

 54 {

 55     printk('<0>function ioctl!nn');

 56     return 0;

 57 }

 58 

 59 static struct file_operations key_fops = {

 60     .owner  =   THIS_MODULE,    /* 這是一個宏,推向編譯模塊時自動創建的__this_module變量 */

 61     .open   =   key_open,

 62     .read   =   key_read,

 63     .write  =   key_write,

 64     .release=   key_release,

 65     .ioctl  =   key_ioctl,

 66 };

 67 

 68 

 69 static int __init  key_irq_init(void)

 70 {

 71     printk('<0>nHello,this is %s module!nn',Driver_NAME);

 72     //register and mknod

 73     major = register_chrdev(0,Driver_NAME,&key_fops);

 74     drv_class = class_create(THIS_MODULE,Driver_NAME);

 75     drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME);  /*/dev/key_query*/

 76     

 77     //kmalloc分配內存實驗1

 78     // buf1 申請一個100字節的物理內存,若無內存,則休眠

 79     buf1 = (unsigned char *)kmalloc(100,GFP_KERNEL);

 80     if(buf1 == NULL){

 81         printk('<0>buf1 kmalloc error !nn');

 82         return -1;

 83     }

 84     printk('<0>buf1 kmalloc mem addr = %x nn',buf1);

 85     memset(buf1,0,100);                                //將所分配到的內存清理

 86     strcpy(buf1,'<<------buf1 Kmalloc Mem OK!------>>');//向內存中寫入數據

 87     printk('<0>BUF1: %snn',buf1);                    //從內存中讀出數據

 88 

 89     //get_zeroed_page申請分配整頁內存,并且初始化為0

 90     buf2 = (unsigned char *)get_zeroed_page(GFP_KERNEL);

 91     if(buf2 == NULL){

 92         printk('<0>buf2 get_zeroed_page error !nn');

 93         return -1;

 94     }

 95     printk('<0>buf2 get_zeroed_page addr = %x nn',buf2);

 96     strcpy(buf2,'<<------buf2 get_zeroed_page OK!------>>');//向內存中寫入數據

 97     printk('<0>BUF2: %snn',buf2);

 98 

 99     //Vmalloc 申請1000000個字節(1M)的空間 虛擬地址分配(零碎的物理地址空間)

100     buf3 = (unsigned char *)vmalloc(1000000);

101     if(buf3 == NULL){

102         printk('<0>buf3 vmalloc error !nn');

103         return -1;

104     }

105     printk('<0>buf3 vmalloc addr = %x nn',buf3);

106     strcpy(buf3,'<<------buf3 vmalloc OK!------>>');//向內存中寫入數據

107     printk('<0>BUF3: %snn',buf3);

108     

109     return 0; 

110 }

111                      

112 static void __exit key_irq_exit(void)

113 {

114     printk('<0>nGoodbye,%s!nn',Driver_NAME);

115 

116        unregister_chrdev(major,Driver_NAME);

117     device_unregister(drv_class_dev);

118     class_destroy(drv_class);

119 

120     //釋放前面申請的內存

121     printk('<0>buf1 kfree addr = %x nn',buf1);

122     kfree(buf1);

[1] [2]
關鍵字:Linux  內存空間  內存分配 引用地址:IMX257 Linux內存空間內存分配

上一篇:IMX257 LED驅動程序實現
下一篇:IMX257 linux設備驅動之Cdev結構

推薦閱讀最新更新時間:2025-06-07 23:40

明晰C內存分配的五種方法的區別
在C 中,內存分成5個區,他們分別是堆、棧、自由存儲區、全局/靜態存儲區和常量存儲區。棧,就是那些由編譯器在需要的時候分配,在不需要的時候自動清楚的變量的存儲區。里面的變量通常是局部變量、函數參數等。 堆,就是那些由new分配的內存塊,他們的釋放編譯器不去管,由我們的應用程序去控制,一般一個new就要對應一個delete。如果程序員沒有釋放掉,那么在程序結束后,操作系統會自動回收。 自由存儲區,就是那些由malloc等分配的內存塊,他和堆是十分相似的,不過它是用free來結束自己的生命的。 全局/靜態存儲區,全局變量和靜態變量被分配到同一塊內存中,在以前的C語言中,全局變量又分為初始化的和未初始化的,在C 里面沒有這個區分了
[單片機]
一種嵌入式系統的內存分配方案
摘要:實時性、可靠性的要求,使得許多嵌入式應用使用自己的內存管理程序。本文探討嵌入式系統中對內存管理的要求、存在的問題以及可能的解決策略;介紹一種“一次分配,多次使用”的動態內存分配方法,并給出2個例子。 關鍵詞:嵌入式系統 內存管理 一次分配多次使用 1 嵌入式系統中對內存分配的要求 ①快速性。嵌入式系統中對實時性的保證,要求內存分配過程要盡可能地快。因此在嵌入式系統中,不可能采用通用操作系統中復雜而完善的內存分配策略,一般都采用簡單、快速的內存分配方案。當然,對實性要求的程序不同,分配方案也有所不同。例如,VxWorks采用簡單的最先匹配如立即聚合方法;VRTX中采用多個固定尺寸的binning方案。 ②可靠性。也就是
[工業控制]
IMX257 總線設備驅動模型編程之總線篇(二)
前面我們講解了一個簡單的總線驅動程序,目的就是在/sys/bus/下面創建文件,但是這還是不夠的,因為總線也是一個設備,如果想讓系統認識的話,必須要用device_register進行注冊。 此處,我們就開始來注冊一個總線,讓總線下即可以包含屬性文件,也包含設備文件,和驅動程序。 讓驅動程序 和設備文件之間互聯,這才是總線真正的用途。 一、程序解析 前面已經將的很詳細,我們這兒在前面的基礎上加上一下: 1. 定義總體設備結構體 并且實現 設備的release函數; 2. 導出總線設備 3. 注冊設備驅動 4. 卸載設備 二、編譯測試: 加載成功后,因為總線也是一個設備,所以在 /sys/bu
[單片機]
<font color='red'>IMX257</font> 總線設備驅動模型編程之總線篇(二)
【IMX6ULL學習筆記】六、U-BOOT環境變量與Linux啟動
一、環境變量 bootcmd bootcmd 和 bootagrs 是采用類似 shell 腳本語言編寫的,里面很多的變量引用,這些變量都是環境變量,很多是 NXP 定義的。文件mx6ull_alientek_emmc.h 中的宏 CONFIG_EXTRA_ENV_SETTINGS 保存著這些環境變量的默認值,內容如下: #if defined(CONFIG_SYS_BOOT_NAND) #define CONFIG_EXTRA_ENV_SETTINGS CONFIG_MFG_ENV_SETTINGS panel=TFT43AB fdt_addr=0x83000000 fdt_high=0xffff
[單片機]
【IMX6ULL學習筆記】六、U-BOOT環境變量與<font color='red'>Linux</font>啟動
ARM-Linux S5PV210 UART驅動(5)----串口的open操作(tty_open、uart_open)
串口驅動初始化后,串口作為字符驅動也已經注冊到系統了,/dev目錄下也有設備文件節點了。 那接下來uart的操作是如何進行的呢? 操作硬件之前都是要先open設備,先來分析下這里的open函數具體做了那些工作。 s3c24xx_serial_modinit -- uart_register_driver -- tty_register_driver 中有如下語句: cdev_init(&driver- cdev, &tty_fops); 此處將 driver- cdev- ops=&tty_fops 而tty_fops如下: static const struct file_operations tty_f
[單片機]
Linux〗OK6410a蜂鳴器的驅動程序編寫全程實錄
最近在看一本書,受益匪淺,作者是李寧,下邊是編寫本次蜂鳴器的全程實錄: 1. 了解開發板中的蜂鳴器  1) 查看蜂鳴器buzzer在底板中的管腳信息  2) 查看蜂鳴器在總線中的信息  3) 翻看S3C6410芯片手冊,查看GPF15相關信息 2. 在了解了開發板中蜂鳴器之后,編寫代碼對它進行控制。  由于蜂鳴器是通過PWM(脈沖寬度調制)進行開關控制的,故也稱為PWM。  1) 編寫pwm.c(包含Linux驅動模塊的主要模型代碼) #include pwm_fun.h static struct semaphore lock; /* 創建信號量*/ //文件打開時,自動操作此函數,使用信號
[單片機]
〖<font color='red'>Linux</font>〗OK6410a蜂鳴器的驅動程序編寫全程實錄
Linux-2.6.39在Tiny6410上的移植
Linux內核版本號:linux 2.6.39 交叉編譯工具:arm-linux-gcc 4.5.1 Linux內核下載:www.kernel.org 開發板:友善之臂Tiny6410 一、解壓內核 tar xzvf linux-2.6.39.tar.gz 二、修改Makefile ARCH ?= $(SUBARCH) CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE: % =%) 改成: ARCH ?= arm CROSS_COMPILE ?= arm-linux- 三、進入解壓出來的linux-2.6.39目錄,拷貝arch/arm/configs/s3c6400_defc
[單片機]
Linux移植之內核啟動過程引導階段分析
在Linux移植之make uImage編譯過程分析中已經提到了uImage是一個壓縮的包并且內含壓縮程序,可以進行自解壓。自解壓完成之后內核代碼從物理地址為0x30008000處開始運行。下面分析在進入C之前內核做的一些工作,以下是內核啟動過程中打印出來的信息,其中Uncompressing Linux就是在自解壓代碼。make uImage編譯的最后也給出了鏈接腳本arch/arm/kernel/vmlinux.lds,以及鏈接的順序arch/arm/kernel/head.o 是第一個。 分析arch/arm/kernel/vmlinux.lds可以知道程序入口的地址是stext,并且是.text.head段 277
[單片機]
<font color='red'>Linux</font>移植之內核啟動過程引導階段分析
小廣播
設計資源 培訓 開發板 精華推薦

最新單片機文章
何立民專欄 單片機及嵌入式寶典

北京航空航天大學教授,20余年來致力于單片機與嵌入式系統推廣工作。

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發圈

 
機器人開發圈

電子工程世界版權所有 京ICP證060456號 京ICP備10001474號-1 電信業務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 余庆县| 西宁市| 华坪县| 湖口县| 屏东县| 观塘区| 申扎县| 台江县| 新巴尔虎左旗| 湖南省| 三明市| 嵩明县| 乌兰浩特市| 南丰县| 霍山县| 鄂托克前旗| 怀安县| 宁德市| 库伦旗| 板桥市| 晴隆县| 龙南县| 锦州市| 武夷山市| 郁南县| 黄浦区| 烟台市| 上高县| 合阳县| 辉县市| 前郭尔| 宝兴县| 蒲江县| 长沙县| 千阳县| 平度市| 泉州市| 玛曲县| 上杭县| 临武县| 通江县|