青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

統計

  • 隨筆 - 50
  • 文章 - 42
  • 評論 - 147
  • 引用 - 0

留言簿(6)

隨筆分類

文章分類

Link

搜索

  •  

積分與排名

  • 積分 - 167188
  • 排名 - 159

最新評論

閱讀排行榜

評論排行榜

kmalloc vmalloc

在設備驅動程序中動態開辟內存,不是用malloc,而是kmalloc,或者用get_free_pages直接申請頁。釋放內存用的是kfree,或free_pages.

   對于提供了MMU(存儲管理器,輔助操作系統進行內存管理,提供虛實地址轉換等硬件支持)的處理器而言,Linux提供了復雜的存儲管理系統,使得進程所能訪問的內存達到4GB。

  進程的4GB內存空間被人為的分為兩個部分--用戶空間與內核空間。用戶空間地址分布從0到3GB(PAGE_OFFSET,在0x86中它等于0xC0000000),3GB到4GB為內核空間。

  內核空間中,從3G到vmalloc_start這段地址是物理內存映射區域(該區域中包含了內核鏡像、物理頁框表mem_map等等),比如我們使用的 VMware虛擬系統內存是160M,那么3G~3G+160M這片內存就應該映射物理內存。在物理內存映射區之后,就是vmalloc區域。對于 160M的系統而言,vmalloc_start位置應在3G+160M附近(在物理內存映射區與vmalloc_start期間還存在一個8M的gap 來防止躍界),vmalloc_end的位置接近4G(最后位置系統會保留一片128k大小的區域用于專用頁面映射)

     kmalloc和get_free_page申請的內存位于物理內存映射區域,而且在物理上也是連續的,它們與真實的物理地址只有一個固定的偏移,因此存在較簡單的轉換關系,virt_to_phys()可以實現內核虛擬地址轉化為物理地址:
   #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
   extern inline unsigned long virt_to_phys(volatile void * address)
   {
        return __pa(address);
   }
上面轉換過程是將虛擬地址減去3G(PAGE_OFFSET=0XC000000)。

與之對應的函數為phys_to_virt(),將內核物理地址轉化為虛擬地址:
   #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
   extern inline void * phys_to_virt(unsigned long address)
   {
        return __va(address);
   }
virt_to_phys()和phys_to_virt()都定義在include\asm-i386\io.h中。

-------------------------------------------------------------------------------------
1、kmalloc() 分配連續的物理地址,用于小內存分配。

  2、__get_free_page() 分配連續的物理地址,用于整頁分配。

  至于為什么說以上函數分配的是連續的物理地址和返回的到底是物理地址還是虛擬地址,下面的記錄會做出解釋。

  kmalloc() 函數本身是基于 slab 實現的。slab 是為分配小內存提供的一種高效機制。但 slab 這種分配機制又不是獨立的,它本身也是在頁分配器的基礎上來劃分更細粒度的內存供調用者使用。也就是說系統先用頁分配器分配以頁為最小單位的連續物理地址,然后 kmalloc() 再在這上面根據調用者的需要進行切分。

  關于以上論述,我們可以查看 kmalloc() 的實現,kmalloc()函數的實現是在 __do_kmalloc() 中,可以看到在 __do_kmalloc()代碼里最終調用了 __cache_alloc() 來分配一個 slab,其實

  kmem_cache_alloc() 等函數的實現也是調用了這個函數來分配新的 slab。我們按照 __cache_alloc()函數的調用路徑一直跟蹤下去會發現在 cache_grow() 函數中使用了 kmem_getpages()函數來分配一個物理頁面,kmem_getpages() 函數中調用的alloc_pages_node() 最終是使用 __alloc_pages() 來返回一個struct page 結構,而這個結構正是系統用來描述物理頁面的。這樣也就證實了上面所說的,slab 是在物理頁面基礎上實現的。kmalloc() 分配的是物理地址。

  __get_free_page() 是頁面分配器提供給調用者的最底層的內存分配函數。它分配連續的物理內存。__get_free_page() 函數本身是基于 buddy 實現的。在使用 buddy 實現的物理內存管理中最小分配粒度是以頁為單位的。關于以上論述,我們可以查看__get_free_page()的實現,可以看到__get_free_page()函數只是一個非常簡單的封狀,它的整個函數實現就是無條件的調用 __alloc_pages() 函數來分配物理內存,上面記錄 kmalloc()實現時也提到過是在調用 __alloc_pages() 函數來分配物理頁面的前提下進行的 slab 管理。那么這個函數是如何分配到物理頁面又是在什么區域中進行分配的?回答這個問題只能看下相關的實現。可以看到在 __alloc_pages() 函數中,多次嘗試調用get_page_from_freelist() 函數從 zonelist 中取得相關 zone,并從其中返回一個可用的 struct page 頁面(這里的有些調用分支是因為標志不同)。至此,可以知道一個物理頁面的分配是從 zonelist(一個 zone 的結構數組)中的 zone 返回的。那么 zonelist/zone 是如何與物理頁面關聯,又是如何初始化的呢?繼續來看 free_area_init_nodes() 函數,此函數在系統初始化時由 zone_sizes_init() 函數間接調用的,zone_sizes_init()函數填充了三個區域:ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM。并把他們作為參數調用 free_area_init_nodes(),在這個函數中會分配一個 pglist_data 結構,此結構中包含了 zonelist/zone結構和一個 struct page 的物理頁結構,在函數最后用此結構作為參數調用了 free_area_init_node() 函數,在這個函數中首先使用 calculate_node_totalpages() 函數標記 pglist_data 相關區域,然后調用 alloc_node_mem_map() 函數初始化 pglist_data結構中的 struct page 物理頁。最后使用 free_area_init_core()函數關聯 pglist_data 與 zonelist。現在通以上分析已經明確了__get_free_page() 函數分配物理內存的流程。但這里又引出了幾個新問題,那就是此函數分配的物理頁面是如何映射的?映射到了什么位置?到這里不得不去看下與 VMM 相關的引導代碼。

  在看 VMM 相關的引導代碼前,先來看一下 virt_to_phys() 與phys_to_virt 這兩個函數。顧名思義,即是虛擬地址到物理地址和物理地址到虛擬地址的轉換。函數實現十分簡單,前者調用了__pa( address ) 轉換虛擬地址到物理地址,后者調用 __va(addrress ) 將物理地址轉換為虛擬地址。再看下 __pa __va 這兩個宏到底做了什么。

  #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
  #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))

  通過上面可以看到僅僅是把地址加上或減去 PAGE_OFFSET,而PAGE_OFFSET 在 x86 下定義為 0xC0000000。這里又引出了疑問,在 linux 下寫過 driver 的人都知道,在使用 kmalloc() 與

  __get_free_page() 分配完物理地址后,如果想得到正確的物理地址需要使用 virt_to_phys() 進行轉換。那么為什么要有這一步呢?我們不分配的不就是物理地址么?怎么分配完成還需要轉換?如果返回的是虛擬地址,那么根據如上對 virt_to_phys() 的分析,為什么僅僅對 PAGE_OFFSET 操作就能實現地址轉換呢?虛擬地址與物理地址之間的轉換不需要查頁表么?代著以上諸多疑問來看 VMM 相關的引導代碼。

  直接從 start_kernel() 內核引導部分來查找 VMM 相關內容。可以看到第一個應該關注的函數是 setup_arch(),在這個函數當中使用paging_init() 函數來初始化和映射硬件頁表(在初始化前已有 8M內存被映射,在這里不做記錄),而 paging_init() 則是調用的pagetable_init() 來完成內核物理地址的映射以及相關內存的初始化。在 pagetable_init() 函數中,首先是一些 PAE/PSE/PGE 相關判斷與設置,然后使用 kernel_physical_mapping_init() 函數來實現內核物理內存的映射。在這個函數中可以很清楚的看到,pgd_idx 是以PAGE_OFFSET 為啟始地址進行映射的,也就是說循環初始化所有物理地址是以 PAGE_OFFSET 為起點的。繼續觀察我們可以看到在 PMD 被初始化后,所有地址計算均是以 PAGE_OFFSET 作為標記來遞增的。分析到這里已經很明顯的可以看出,物理地址被映射到以 PAGE_OFFSET 開始的虛擬地址空間。這樣以上所有疑問就都有了答案。kmalloc() 與__get_free_page() 所分配的物理頁面被映射到了 PAGE_OFFSET 開始的虛擬地址,也就是說實際物理地址與虛擬地址有一組一一對應的關系,

  正是因為有了這種映射關系,對內核以 PAGE_OFFSET 啟始的虛擬地址的分配也就是對物理地址的分配(當然這有一定的范圍,應該在 PAGE_OFFSET與 VMALLOC_START 之間,后者為 vmalloc() 函數分配內存的啟始地址)。這也就解釋了為什么 virt_to_phys() 與 phys_to_virt() 函數的實現僅僅是加/減 PAGE_OFFSET 即可在虛擬地址與物理地址之間轉換,正是因為了有了這種映射,且固定不變,所以才不用去查頁表進行轉換。這也同樣回答了開始的問題,即 kmalloc() / __get_free_page() 分配的是物理地址,而返回的則是虛擬地址(雖然這聽上去有些別扭)。正是因為有了這種映射關系,所以需要將它們的返回地址減去 PAGE_OFFSET 才可以得到真正的物理地址。

另一篇更容易理解的:

kmalloc, vmalloc分配的內存結構 zz
2008-01-20 16:05
進程空間:| <-用戶空間-> | <-內核空間-> |
內核空間:| <-物理內存映射區-> | <-vmalloc區域-> |

==============原文================================

   對于提供了MMU(存儲管理器,輔助操作系統進行內存管理,提供虛實地址轉換等硬件支持)的處理器而言,Linux提供了復雜的存儲管理系統,使得進程所能訪問的內存達到4GB。

進程的4GB內存空間被人為的分為兩個部分--用戶空間與內核空間。用戶空間地址分布從0到3GB(PAGE_OFFSET,在0x86中它等于0xC0000000),3GB到4GB為內核空間。

內核空間中,從3G到vmalloc_start這段地址是物理內存映射區域(該區域中包含了內核鏡像、物理頁框表mem_map等等),比如我們使用 的 VMware虛擬系統內存是160M,那么3G~3G+160M這片內存就應該映射物理內存。在物理內存映射區之后,就是vmalloc區域。對于 160M的系統而言,vmalloc_start位置應在3G+160M附近(在物理內存映射區與vmalloc_start期間還存在一個8M的gap 來防止躍界),vmalloc_end的位置接近4G(最后位置系統會保留一片128k大小的區域用于專用頁面映射)

kmalloc和get_free_page申請的內存位于物理內存映射區域,而且在物理上也是連續的,它們與真實的物理地址只有一個固定的偏移,因此存在較簡單的轉換關系,virt_to_phys()可以實現內核虛擬地址轉化為物理地址:
   #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
   extern inline unsigned long virt_to_phys(volatile void * address)
   {
        return __pa(address);
   }
上面轉換過程是將虛擬地址減去3G(PAGE_OFFSET=0XC000000)。

與之對應的函數為phys_to_virt(),將內核物理地址轉化為虛擬地址:
   #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
   extern inline void * phys_to_virt(unsigned long address)
   {
        return __va(address);
   }
virt_to_phys()和phys_to_virt()都定義在include\asm-i386\io.h中。

而vmalloc申請的內存則位于vmalloc_start~vmalloc_end之間,與物理地址沒有簡單的轉換關系,雖然在邏輯上它們也是連續的,但是在物理上它們不要求連續。

我們用下面的程序來演示kmalloc、get_free_page和vmalloc的區別:
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
MODULE_LICENSE("GPL");
unsigned char *pagemem;
unsigned char *kmallocmem;
unsigned char *vmallocmem;

int __init mem_module_init(void)
{
//最好每次內存申請都檢查申請是否成功
//下面這段僅僅作為演示的代碼沒有檢查
pagemem = (unsigned char*)get_free_page(0);
printk("<1>pagemem addr=%x", pagemem);

kmallocmem = (unsigned char*)kmalloc(100, 0);
printk("<1>kmallocmem addr=%x", kmallocmem);

vmallocmem = (unsigned char*)vmalloc(1000000);
printk("<1>vmallocmem addr=%x", vmallocmem);

return 0;
}

void __exit mem_module_exit(void)
{
free_page(pagemem);
kfree(kmallocmem);
vfree(vmallocmem);
}

module_init(mem_module_init);
module_exit(mem_module_exit);

我們的系統上有160MB的內存空間,運行一次上述程序,發現pagemem的地址在0xc7997000(約3G+121M)、kmallocmem 地址在0xc9bc1380(約3G+155M)、vmallocmem的地址在0xcabeb000(約3G+171M)處,符合前文所述的內存布局。

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/sandflee/archive/2009/07/28/4388322.aspx

posted on 2009-11-17 17:18 pear_li 閱讀(1367) 評論(0)  編輯 收藏 引用 所屬分類: Linux/Unix

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久精品亚洲一区二区| 国内久久婷婷综合| 亚洲男人第一av网站| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 国产麻豆9l精品三级站| 国产精品久久久久久户外露出| 欧美午夜电影在线观看| 国产精品亚洲一区二区三区在线| 欧美欧美在线| 国产精品久久久久久妇女6080| 国产无一区二区| 在线精品视频免费观看| 亚洲欧洲一区二区天堂久久 | 99在线精品观看| 亚洲性av在线| 久久久久久久综合| 欧美大胆成人| 国产精品捆绑调教| 亚洲国产成人在线视频| 一区二区三区视频在线看 | 亚洲国产精品成人| 日韩午夜在线电影| 香蕉成人久久| 欧美成人午夜免费视在线看片| 欧美日韩精品一区二区天天拍小说 | 一区二区高清视频| 久久成人免费| 欧美日韩高清在线播放| 国产视频不卡| 亚洲小视频在线| 蜜桃久久av一区| 亚洲一区二区三区精品动漫| 免费观看在线综合| 国产精品资源| 在线综合+亚洲+欧美中文字幕| 久久人人爽人人爽爽久久| 亚洲精品国产视频| 看片网站欧美日韩| 国产日本欧美一区二区三区| 亚洲三级视频| 你懂的视频欧美| 亚洲欧美制服另类日韩| 欧美精品一区二区在线观看 | 亚洲影院色无极综合| 欧美成人在线网站| 欧美一区二区三区久久精品| 欧美午夜激情小视频| aa国产精品| 国产精品精品视频| 亚洲午夜激情网页| 亚洲青色在线| 欧美11—12娇小xxxx| 在线观看91精品国产入口| 欧美资源在线观看| 亚洲欧美久久久久一区二区三区| 欧美日韩中文在线| 亚洲免费伊人电影在线观看av| 亚洲国产精品久久久久秋霞影院| 久久精品国产精品亚洲| 国内精品视频在线观看| 欧美在线三级| 夜夜嗨av一区二区三区网站四季av| 久久免费一区| 一区二区三区四区国产精品| 免费看精品久久片| 在线看欧美视频| 久久综合久色欧美综合狠狠| 性久久久久久| 国产视频精品xxxx| 久久成人精品一区二区三区| 亚洲欧美www| 国产美女一区二区| 久久国产一二区| 欧美一区二区三区视频免费| 国产一区二区三区的电影| 久久久久www| 久久aⅴ乱码一区二区三区| 国产毛片精品国产一区二区三区| 午夜精品久久久久久久白皮肤 | 欧美在线观看你懂的| 欧美亚洲免费电影| 好吊日精品视频| 欧美国产视频日韩| 欧美体内谢she精2性欧美| 亚洲欧美日韩一区二区三区在线| 亚洲女与黑人做爰| 亚洲精品1234| 一二三区精品福利视频| 亚洲一区二区三区精品视频 | 亚洲素人在线| 欧美一区二区三区在线播放| 揄拍成人国产精品视频| 欧美国产欧美综合 | 亚洲精品综合久久中文字幕| 亚洲人在线视频| 国产精品欧美激情| 欧美激情精品久久久久久蜜臀| 欧美激情女人20p| 午夜亚洲性色视频| 蜜桃av噜噜一区| 亚洲一区黄色| 久久亚洲欧美| 亚洲一区二区黄色| 久久青青草原一区二区| 亚洲女性裸体视频| 蜜臀av性久久久久蜜臀aⅴ四虎 | 国产日韩精品视频一区| 亚洲国产欧美精品| 国产欧美日韩综合一区在线播放| 欧美电影在线免费观看网站| 国产精品久久久久毛片软件| 欧美电影免费观看网站| 国产精品一区在线观看你懂的| 狠久久av成人天堂| av成人免费在线观看| 性欧美暴力猛交另类hd| 在线亚洲激情| 女生裸体视频一区二区三区| 久久超碰97人人做人人爱| 欧美日韩精品免费看| 欧美激情一区二区三区在线视频观看| 国产精品入口日韩视频大尺度| 欧美激情一区二区三区全黄| 狠狠色狠狠色综合日日小说| 一级日韩一区在线观看| 一本久久知道综合久久| 久久亚洲春色中文字幕| 久久久久久香蕉网| 国模叶桐国产精品一区| 亚洲一级片在线观看| 一区二区三区免费看| 欧美第一黄色网| 欧美成在线视频| 最新69国产成人精品视频免费| 久久九九热re6这里有精品| 久久精品一区二区| 国产日韩欧美夫妻视频在线观看| 一本色道久久综合亚洲91| 亚洲一区欧美二区| 国产精品久久久久av| 亚洲视频在线一区| 午夜视频在线观看一区二区三区 | 免费成人av在线看| 国内精品免费在线观看| 久久av一区| 欧美成人激情在线| 亚洲电影成人| 免费成人高清视频| 91久久精品国产91久久性色tv | 欧美激情第4页| 亚洲日本免费| 一区二区电影免费在线观看| 欧美日韩国产成人高清视频| 狠狠色丁香婷婷综合久久片| 欧美在线视频二区| 欧美成人a视频| 亚洲激情国产| 国产精品国色综合久久| 午夜精品视频一区| 猫咪成人在线观看| 一区二区三区黄色| 国产久一道中文一区| 榴莲视频成人在线观看| 欧美国产日本在线| 亚洲欧美国产一区二区三区| 国产一区二区久久精品| 久久婷婷国产综合国色天香| 亚洲精品女av网站| 一本色道久久综合亚洲精品小说 | 久久久国际精品| 亚洲国产精品电影在线观看| 欧美二区不卡| 亚洲电影免费观看高清| 欧美日本一区二区视频在线观看| 亚洲一区二区三区乱码aⅴ| 国产精品久久久久久妇女6080 | 午夜一区不卡| 欧美成人精品高清在线播放| 一区二区av| 国产自产女人91一区在线观看| 欧美成ee人免费视频| 亚洲在线视频一区| 欧美成人亚洲成人日韩成人| 亚洲一区二区精品视频| 亚洲第一中文字幕在线观看| 国产精品爽爽爽| 牛夜精品久久久久久久99黑人| 一区二区欧美在线| 欧美激情一区二区三区在线| 久久精品1区| 亚洲欧美激情视频在线观看一区二区三区| 国产嫩草一区二区三区在线观看| 欧美激情第1页| 久久亚洲春色中文字幕久久久| 亚洲一区二区黄色| 亚洲精品欧洲精品| 精品1区2区3区4区| 国产精品久久久久高潮| 欧美日韩你懂的| 欧美成人一区在线|