⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linux设备驱动程序学习(8)-分配内存 - linux设备驱动程序 - tekkaman ninja.htm

📁 Linux设备驱动程序学习(8)-分配内存 - Linux设备驱动程序.rar
💻 HTM
📖 第 1 页 / 共 5 页
字号:
                              <P><FONT color=#0000ff><FONT color=#000000>kmalloc 
                              是一个功能强大且高速(除非被阻塞)的工具,所分配到的内存在物理内存中连续且保持原有的数据(不清零)。原型:</FONT></FONT></P>
                              <TABLE style="BORDER-COLLAPSE: collapse" 
                              borderColor=#999999 cellSpacing=0 cellPadding=0 
                              width="95%" bgColor=#f1f1f1 border=1>
                                <TBODY>
                                <TR>
                                <TD>
                                <P 
                                style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN 
                                style="COLOR: #000000">#<SPAN 
                                style="COLOR: #ff0000">include</SPAN> <SPAN 
                                style="COLOR: #0000cc">&lt;</SPAN>linux/slab<SPAN 
                                style="COLOR: #0000cc">.</SPAN>h<SPAN 
                                style="COLOR: #0000cc">&gt;</SPAN> <BR>void 
                                <SPAN 
                                style="COLOR: #0000cc">*</SPAN>kmalloc<SPAN 
                                style="COLOR: #0000cc">(</SPAN>size_t <SPAN 
                                style="COLOR: #0000ff">size</SPAN><SPAN 
                                style="COLOR: #0000cc">,</SPAN> <SPAN 
                                style="COLOR: #0000ff">int</SPAN> flags<SPAN 
                                style="COLOR: #0000cc">)</SPAN><SPAN 
                                style="COLOR: #0000cc">;</SPAN> 
                                </SPAN></CODE></P></TD></TR></TBODY></TABLE>
                              <P><FONT color=#0000ff><STRONG>size 
                              参数</STRONG></FONT></P>
                              <P>内核管理系统的物理内存,物理内存只能按页面进行分配。kmalloc 和典型的用户空间 
                              malloc 在实际上有很大的差别,内核使用特殊的基于页的分配技术,以最佳的方式利用系统 
                              RAM。Linux 
                              处理内存分配的方法:创建一系列内存对象集合,每个集合内的内存块大小是固定。处理分配请求时,就直接在包含有足够大内存块的集合中传递一个整块给请求者。</P>
                              <P>必须注意的是:内核只能分配一些预定义的、固定大小的字节数组。kmalloc 
                              能够处理的最小内存块是 32 或 64 
                              字节(体系结构依赖),而内存块大小的上限随着体系和内核配置而变化。考虑到移植性,不应分配大于 128 
                              KB的内存。若需多于几个 KB的内存块,最好使用其他方法。</P>
                              <P><STRONG><FONT 
                              color=#0000ff>flags&nbsp;参数</FONT></STRONG></P>
                              <P>内存分配最终总是调用 __get_free_pages 来进行实际的分配,这就是 GFP_ 
                              前缀的由来。</P>
                              <P>所有标志都定义在 <FONT 
                              color=#0000ff>&lt;linux/gfp.h&gt;</FONT> 
                              ,有符号代表常常使用的标志组合。</P>
                              <P>主要的标志常被称为分配优先级,包括:</P>
                              <DIV class=variablelist>
                              <DL><SPAN class=term>
                                <DT><SPAN class=term><FONT 
                                color=#0000ff>GFP_KERNEL</FONT> 
                                <SPAN></SPAN></SPAN>
                                <DD>
                                <P>最常用的标志,意思是这个分配代表运行在内核空间的进程进行。内核正常分配内存。当空闲内存较少时,可能进入休眠来等待一个页面。当前进程休眠时,内核会采取适当的动作来获取空闲页。所以使用 
                                GFP_KERNEL 来分配内存的函数必须是可重入,且不能在原子上下文中运行。</P>
                                <DT><FONT color=#0000ff>GFP_ATOMIC</FONT> 
                                <SPAN></SPAN></SPAN>
                                <DD>
                                <P>内核通常会为原子性的分配预留一些空闲页。当当前进程不能被置为睡眠时,应使用 
                                GFP_ATOMIC,这样kmalloc 
                                甚至能够使用最后一个空闲页。如果连这最后一个空闲页也不存在,则分配返回失败。常用来从中断处理和进程上下文之外的其他代码中分配内存,从不睡眠。</P>
                                <DT><SPAN class=term><FONT 
                                color=#0000ff>GFP_USER</FONT> 
                                <SPAN></SPAN></SPAN>
                                <DD>
                                <P>用来为用户空间分配内存页,可能睡眠。</P>
                                <DT><SPAN class=term><FONT 
                                color=#0000ff>GFP_HIGHUSER</FONT> 
                                <SPAN></SPAN></SPAN>
                                <DD>
                                <P>类似&nbsp;GFP_USER,如果有高端内存,就从高端内存分配。</P>
                                <DT><SPAN class=term><FONT 
                                color=#0000ff>GFP_NOIO 
                                <SPAN></SPAN></FONT></SPAN>
                                <DD><FONT color=#0000ff></FONT>
                                <DT><SPAN class=term><FONT 
                                color=#0000ff>GFP_NOFS</FONT> 
                                <SPAN></SPAN></SPAN>
                                <DD>
                                <P>功能类似 GFP_KERNEL,但是为内核分配内存的工作增加了限制。具有GFP_NOFS 
                                的分配不允许执行任何文件系统调用,而 GFP_NOIO 禁止任何 I/O 
                                初始化。它们主要用在文件系统和虚拟内存代码。那里允许分配休眠,但不应发生递归的文件系统调。</P></DD></DL></DIV>
                              <P><FONT color=#660099>
                              <TABLE 
                              style="BORDER-RIGHT: #999 1px solid; BORDER-TOP: #999 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #999 1px solid; WIDTH: 94.38%; BORDER-BOTTOM: #999 1px solid; HEIGHT: 237px" 
                              align=center>
                                <TBODY>
                                <TR>
                                <TD>
                                <P>Linux 内核把内存分为 3 个区段: 
                                可用于DMA的内存(位于一个特别的地址范围的内存, 外设可以在这里进行 DMA 
                                存取)、常规内存和高端内存(为了访问(相对)大量的内存而存在的一种机制)。目的是使每中计算机平台都必须知道如何将自己特定的内存范围归类到这三个区段中,而不是所有RAM都一样。</P>
                                <P>当要分配一个满足kmalloc要求的新页时, 
                                内核会建立一个内存区段的列表以供搜索。若指定了 __GFP_DMA, 
                                只有可用于DMA的内存区段被搜索;若没有指定特别的标志, 常规和 
                                可用于DMA的内存区段都被搜索; 若 设置了 __GFP_HIGHMEM,所有的 3 
                                个区段都被搜索(注意:kmalloc 不能分配高端内存)。</P>
                                <P>内存区段背后的机制在 mm/page_alloc.c 中实现, 
                                且区段的初始化时平台相关的, 通常在 arch 目录树的 
                                mm/init.c中。</P></TD></TR></TBODY></TABLE></FONT></P>
                              <P><FONT 
                              color=#660099>有的标志用双下划线做前缀,他们可与上面标志“或”起来使用,以控制分配方式:</FONT></P>
                              <DIV class=variablelist>
                              <DL>
                                <DT><SPAN class=term><FONT 
                                color=#0000ff>__GFP_DMA</FONT> 
                                <SPAN></SPAN></SPAN>
                                <DD>
                                <P>要求分配可用于DMA的内存。</P>
                                <DT><SPAN class=term><FONT 
                                color=#0000ff>__GFP_HIGHMEM</FONT> 
                                <SPAN></SPAN></SPAN>
                                <DD>
                                <P>分配的内存可以位于高端内存.</P>
                                <DT><SPAN class=term><FONT 
                                color=#0000ff>__GFP_COLD</FONT> 
                                <SPAN></SPAN></SPAN>
                                <DD>
                                <P>通常,分配器试图返回“缓存热(cache warm)”页面(可在处理器缓存中找到的页面)。 
                                而这个标志请求一个尚未使用的“冷”页面。对于用作 DMA 
                                读取的页面分配,可使用此标志。因为此时页面在处理器缓存中没多大帮助。</P>
                                <DT><SPAN class=term><FONT 
                                color=#0000ff>__GFP_NOWARN</FONT> 
                                <SPAN></SPAN></SPAN>
                                <DD>
                                <P>当一个分配无法满足,阻止内核发出警告(使用 printk )。</P>
                                <DT><SPAN class=term><FONT 
                                color=#0000ff>__GFP_HIGH</FONT> 
                                <SPAN></SPAN></SPAN>
                                <DD>
                                <P>高优先级请求,允许为紧急状况消耗被内核保留的最后一些内存页。</P>
                                <DT><FONT color=#0000ff><SPAN 
                                class=term>__GFP_REPEAT<SPAN></SPAN></SPAN> 
                                </FONT>
                                <DD><FONT color=#0000ff></FONT>
                                <DT><FONT color=#0000ff><SPAN 
                                class=term>__GFP_NOFAIL<SPAN></SPAN></SPAN> 
                                </FONT>
                                <DD><FONT color=#0000ff></FONT>
                                <DT><SPAN class=term><FONT 
                                color=#0000ff>__GFP_NORETRY</FONT> 
                                <SPAN></SPAN></SPAN>
                                <DD>
                                <P>告诉分配器当满足一个分配有困难时,如何动作。__GFP_REPEAT&nbsp;表示努力再尝试一次,仍然可能失败; 
                                __GFP_NOFAIL 告诉分配器尽最大努力来满足要求,始终不返回失败,不推荐使用; 
                                __GFP_NORETRY 告知分配器如果无法满足请求,立即返回。</P>
                                <DD><FONT 
                              color=#0000ff></FONT></DD></DL></DIV><FONT 
                              color=#0000ff><SPAN class=term>
                              <P>
                              <HR id=null>

                              <P></P></SPAN></FONT>
                              <DL>
                                <DT><FONT color=#0000ff size=4><SPAN 
                                class=term><STRONG>后备高速缓存</STRONG></SPAN></FONT> 

                                <DT><FONT color=#0000ff><SPAN class=term>
                                <P><FONT 
                                color=#000000>内核为驱动程序常常需要反复分配许多相同大小内存块的情况,增加了一些特殊的内存池,称为后备高速缓存(lookaside 
                                cache)。 设备驱动程序通常不会涉及后备高速缓存,但是也有例外:在 Linux 2.6 中 
                                USB 和 SCSI 驱动。</FONT></SPAN></FONT><FONT 
                                color=#0000ff><SPAN class=term><FONT 
                                color=#000000>Linux 内核的高速缓存管理器有时称为“slab 
                                分配器”,相关函数和类型在 <FONT 
                                color=#0000ff>&lt;linux/slab.h&gt;</FONT> 
                                中声明。slab 分配器实现的高速缓存具有 kmem_cache_t 
                                类型。实现过程如下:</FONT></SPAN></FONT></P>
                                <DT>
                                <P><FONT color=#0000ff><SPAN class=term><FONT 
                                color=#000000>(1)创建一个新的后备高速缓存 
                                <TABLE style="BORDER-COLLAPSE: collapse" 
                                borderColor=#999999 cellSpacing=0 cellPadding=0 
                                width="95%" bgColor=#f1f1f1 border=1>
                                <TBODY>
                                <TR>
                                <TD>
                                <P 
                                style="MARGIN: 5px; LINE-HEIGHT: 150%"><CODE><SPAN 
                                style="COLOR: #000000"><FONT 
                                face=新宋体>kmem_cache_t <SPAN 
                                style="COLOR: #0000cc">*</SPAN>kmem_cache_create<SPAN 
                                style="COLOR: #0000cc">(</SPAN><SPAN 
                                style="COLOR: #0000ff">const</SPAN> <SPAN 
                                style="COLOR: #0000ff">char</SPAN> <SPAN 
                                style="COLOR: #0000cc">*</SPAN>name<SPAN 
                                style="COLOR: #0000cc">,</SPAN>&nbsp;</FONT></SPAN></CODE><CODE><SPAN 
                                style="COLOR: #000000"><FONT face=新宋体><SPAN 
                                style="COLOR: #ff0000">size_t</SPAN> size<SPAN 
                                style="COLOR: #0000cc">,</SPAN><SPAN 
                                style="COLOR: #ff0000">size_t</SPAN> offset<SPAN 
                                style="COLOR: #0000cc">,</SPAN><BR>&nbsp;<SPAN 
                                style="COLOR: #0000ff">                 unsigned</SPAN> 
                                <SPAN style="COLOR: #0000ff">long</SPAN> 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -