Linux內核中動態內存分配函數解析

在C語言中,動態內存分配通常用于在運行時申請內存。在內核編程中,動態內存分配與用戶空間有所不同,因為內核需要更謹慎地處理內存,且不能使用用戶空間的庫(如glibc)。下面我們將詳細分析Linux內核中動態申請內存的函數及其區別。

Linux內核中動態內存分配函數

1. kmalloc

kmalloc函數用于在內核空間申請一塊連續的內存區域。它的原型如下:

void *kmalloc(size_t size, gfp_t flags);
  • 參數
    • size:要分配的內存大小(以字節為單位)。
    • flags:分配標志,用于指定分配內存的行為和內存類型(例如GFP_KERNELGFP_ATOMIC等)。
  • 返回值:成功時返回指向分配內存的指針,失敗時返回NULL
  • 特點
    • 分配的內存是物理上連續的(在虛擬地址空間也是連續的)。
    • 分配的大小有限制(通常最大為4MB,但具體取決于配置和架構)。
    • 適用于需要小塊連續內存的情況(如結構體、緩沖區等)。

2. kzalloc

kzallockmalloc的一個變種,它在分配內存的同時將內存初始化為0。原型如下:

void *kzalloc(size_t size, gfp_t flags);
  • 它等價于先用kmalloc分配內存,然后用memset清零。
  • 參數和返回值與kmalloc相同。

3. vmalloc

vmalloc用于分配大塊連續虛擬內存(物理內存不一定連續)。原型如下:

void *vmalloc(unsigned long size);
  • 參數
    • size:要分配的內存大小(以字節為單位)。
  • 返回值:成功時返回虛擬地址連續的指針,失敗時返回NULL
  • 特點
    • 分配的內存虛擬地址連續,但物理地址可能不連續。
    • 分配的內存可以很大(遠大于kmalloc的限制)。
    • 訪問速度可能比kmalloc慢,因為需要建立頁表映射,且可能引起TLB抖動。
    • 適用于需要大塊內存且不需要物理連續性的情況(如模塊加載、大型緩沖區等)。

4. kcalloc

kcalloc用于分配數組內存,并將內存初始化為0。原型如下:

void *kcalloc(size_t n, size_t size, gfp_t flags);
  • 參數
    • n:數組元素個數。
    • size:每個元素的大小。
    • flags:同kmalloc
  • 返回值:成功返回指針,失敗返回NULL
  • 它分配的內存大小為n * size,并初始化為0。

5. alloc_pages / __get_free_pages

這兩個函數用于直接分配頁面(以頁為單位)。

  • alloc_pages返回struct page *,而__get_free_pages返回虛擬地址。
  • 原型:
    struct page *alloc_pages(gfp_t gfp_mask, unsigned int order);
    unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
    
  • 參數
    • gfp_mask:分配標志。
    • order:指定分配頁數的對數(即分配頁數為2^order)。
  • 它們分配的內存是物理連續的,適用于大塊內存需求(但比vmalloc高效,因為物理連續)。

6. kmem_cache_alloc

用于從特定的內存緩存中分配對象。內核中經常需要頻繁分配和釋放相同大小的內存塊(如結構體),使用slab分配器可以提高效率。

  • 首先需要創建一個緩存:
    struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align, unsigned long flags, void (*ctor)(void *));
    
  • 然后從緩存中分配:
    void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags);
    
  • 釋放對象到緩存:
    void kmem_cache_free(struct kmem_cache *cachep, void *objp);
    
  • 銷毀緩存:
    void kmem_cache_destroy(struct kmem_cache *cachep);
    

區別對比

函數物理連續虛擬連續最大大小適用場景速度
kmalloc/kzalloc較小(如4MB)小內存、需要物理連續
vmalloc很大(如多個GB)大內存、不需要物理連續
kcalloc同kmalloc數組分配并初始化為0
alloc_pages較大(多頁)大塊物理連續內存
kmem_cache_alloc是(通常)由緩存對象決定頻繁分配釋放固定大小對象非常快

分配標志(gfp_t flags)常用值

  • GFP_KERNEL:常規分配,可能睡眠(阻塞),適用于進程上下文。
  • GFP_ATOMIC:原子分配,不會睡眠,適用于中斷上下文或不能睡眠的地方。
  • GFP_USER:為用戶空間分配內存。
  • GFP_HIGHUSER:從高端內存為用戶空間分配。
  • GFP_NOIO:禁止I/O操作(在存儲管理代碼中使用)。
  • GFP_NOFS:禁止文件系統操作(在文件系統代碼中使用)。
  • GFP_DMA:分配可用于DMA的內存(物理地址在16MB以下)。
  • GFP_DMA32:分配可用于DMA的內存(物理地址在4GB以下)。

使用注意事項

  1. 上下文要求:在中斷上下文、軟中斷、持有自旋鎖等原子上下文中,不能使用可能睡眠的函數(如GFP_KERNEL),而應使用GFP_ATOMIC
  2. 內存泄漏:內核內存不會自動釋放,必須顯式釋放,否則會導致內存泄漏。
  3. 碎片問題:頻繁分配釋放內存可能導致碎片,使用slab分配器可以減少碎片。
  4. 性能考量vmalloc分配的內存訪問速度相對較慢,應避免在性能關鍵路徑中使用。

釋放內存的函數

  • kmalloc/kzalloc/kcalloc分配的內存用kfree釋放。
  • vmalloc分配的內存用vfree釋放。
  • __get_free_pages分配的內存用free_pages釋放。
  • alloc_pages分配的內存用__free_pages釋放。
  • kmem_cache_alloc分配的內存用kmem_cache_free釋放。

示例代碼片段

// 使用kmalloc
void *ptr = kmalloc(100, GFP_KERNEL);
if (ptr) {// 使用內存kfree(ptr);
}
// 使用vmalloc
void *vptr = vmalloc(1000000);
if (vptr) {// 使用內存vfree(vptr);
}
// 使用內存緩存
struct kmem_cache *my_cache = kmem_cache_create("my_cache", sizeof(struct my_struct), 0, 0, NULL);
struct my_struct *obj = kmem_cache_alloc(my_cache, GFP_KERNEL);
if (obj) {// 使用對象kmem_cache_free(my_cache, obj);
}
kmem_cache_destroy(my_cache);

以上是Linux內核中動態內存分配的主要函數及其區別。在實際使用中,應根據具體需求選擇合適的內存分配函數。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/92628.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/92628.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/92628.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Next.js 中配置不同頁面布局方案

在 Next.js 應用中,你可以通過多種方式實現某些頁面全屏、某些頁面帶菜單/頁眉/頁腳的需求。以下是幾種實現方案: 方案一:使用多個布局組件 1. 創建不同的布局組件 // app/default-layout.tsx import Header from /components/header; import…

Spring Boot 使用外置 Servlet 容器:從配置到部署全指南

在 Spring Boot 開發中,我們通常使用嵌入式 Servlet 容器(如 Tomcat),它能將應用打包成可執行 JAR,簡化部署流程。但在某些場景下(如需要支持 JSP、復雜的容器定制或企業級部署規范)&#xff0c…

借助AI學習開源代碼git0.7之九diff-files

借助AI學習開源代碼git0.7之九diff-files diff-files.c 是一個用于比較工作目錄中的文件和 Git 索引(暫存區)中文件的工具。 實質上,它是 git diff命令在不指定特定提交時功能的核心實現。 主要功能分析: 1. 核心功能 diff-files …

社區資源媒體管理系統設計與實現

社區資源媒體管理系統設計與實現 1. 系統概述 社區資源媒體管理系統是一個專為社區戶外廣告打造的高效、專業化平臺,旨在實現社區媒體的數字化管理、智能投放和便捷交易。該系統將整合社區各類廣告資源,為廣告主、物業公司和社區居民提供一站式服務。 1.…

12.1.6 weak_ptr

weak_ptr weak_ptr會指向一個share_ptr&#xff08;使用一個share_ptr來初始化weak_ptr&#xff09;&#xff0c;但并不會增加這個share_ptr的引用計數器&#xff0c;其析構也不會減少share_ptr的引用計數器。 構造函數及使用 #include <iostream> #include <memory&g…

深度分析Java內存模型

Java 內存模型&#xff08;Java Memory Model, JMM&#xff09;是 Java 并發編程的核心基石&#xff0c;它定義了多線程環境下線程如何與主內存&#xff08;Main Memory&#xff09;以及線程的本地內存&#xff08;工作內存&#xff0c;Working Memory&#xff09;交互的規則。…

代碼隨想錄算法訓練營第五十二天|圖論part3

101. 孤島的總面積 題目鏈接&#xff1a;101. 孤島的總面積 文章講解&#xff1a;代碼隨想錄 思路&#xff1a; 與島嶼面積差不多&#xff0c;區別是再dfs的時候&#xff0c;如果碰到越界的&#xff0c;需要用一個符號標記這不是孤島再continue #include <iostream> #i…

前端實現 excel 數據導出,封裝方法支持一次導出多個Sheet

一、前言 后臺管理項目有時會有需要前端導出excel表格的功能&#xff0c;有時還需要導出多個sheet&#xff0c;并給每個sheet重新命名&#xff0c;下面我們就來實現一下。 二、實現效果圖 三、實現步驟 1、 安裝 命令行安裝 xlsx 和 file-saver npm install xlsx -S npm i…

【Lambda 表達式】返回值為什么是auto

一個例子&#xff1a; int x 10; auto add_x [x](int y) -> int {return x y; }; int result add_x(5); // 結果是 15lambda 是匿名類型&#xff0c;必須用 auto 來接收。&#xff08;必須寫auto&#xff0c;不可省略&#xff09;內層 -> auto 是函數的返回類型自動推…

【小董談前端】【樣式】 CSS與樣式庫:從實現工具到設計思維的跨越

CSS與樣式庫&#xff1a;從實現工具到設計思維的跨越 一、CSS的本質&#xff1a;樣式實現的「施工隊」 CSS作為網頁樣式的描述語言&#xff0c;其核心能力在于&#xff1a; 精確控制元素的尺寸、位置、顏色實現響應式布局和動畫效果與HTML/JavaScript協同完成交互體驗 但CS…

MTSC2025參會感悟:大模型 + CV 重構全終端 UI 檢測技術體系

目錄 一、傳統 UI 自動化的困局:高成本與低效率的雙重枷鎖 1.1 根深蒂固的技術痛點 1.2 多維度質量挑戰的疊加 二、Page eyes 1.0:純視覺方案破解 UI 檢測困局 2.1 純視覺檢測的核心理念 2.2 頁面加載完成的智能判斷 2.3 視覺模型驅動的異常檢測 2.4 大模型賦能未知異…

使用Claude Code從零到一打造一個現代化的GitHub Star項目管理器

在日常的開發工作中&#xff0c;我們經常會在GitHub上star一些有用的項目庫。隨著時間的推移&#xff0c;star的項目越來越多&#xff0c;如何有效管理這些項目成為了一個痛點。 今天&#xff0c;分享我使用Claude Code從零構建的一個GitHub Star管理插件。項目背景與需求分析 …

為什么 Linux 啟動后還能升級內核?

? 為什么 Linux 啟動后還能升級內核&#xff1f; 簡單結論&#xff1a; 因為 “安裝/升級內核 ≠ 當前就使用該內核”&#xff0c;Linux允許你安裝多個內核版本&#xff0c;并在下次啟動時選擇其中一個來加載運行。 &#x1f9e0; 舉個現實生活類比 你在穿一件衣服&#xff08…

Go語言實戰案例-統計文件中每個字母出現頻率

以下是《Go語言100個實戰案例》中的 文件與IO操作篇 - 案例19&#xff1a;統計文件中每個字母出現頻率 的完整內容。本案例適合用來練習文件讀取、字符處理、map統計等基礎技能。&#x1f3af; 案例目標讀取一個本地文本文件&#xff0c;統計并打印出其中每個英文字母&#xff…

Notepad++工具操作技巧

1、notepad -> ctrlf -> 替換(正則表達式) -> $-a ->每行的行尾加a&#xff1b; 2、notepad -> ctrlf -> 替換(正則表達式) -> ^-a ->每行的行首加a &#xff1b; 3、按住alt切換為列模式 4、刪除空行-不包括有空格符號的空行 查找替代 查找目標…

領碼課堂 | Java與AI的“硬核“交響曲:當企業級工程思維遇上智能時代

摘要 &#x1f680; 在AI工業化落地的深水區&#xff0c;Java正以其獨特的工程化優勢成為中流砥柱。本文系統解構Java在AI項目全生命周期中的技術矩陣&#xff0c;通過"三階性能優化模型"、"微服務化AI部署架構"等原創方法論&#xff0c;結合大模型部署、M…

面經 - 基于Linux的高性能在線OJ平臺

真實面試環境中&#xff0c;被問到的相關問題&#xff0c;感興趣的可以看下1. 這個項目是你獨立完成的嗎&#xff1f;團隊中你的職責是什么&#xff1f;是的&#xff0c;這個項目是我獨立完成的&#xff0c;從需求分析、系統設計到項目部署都我做的。重點工作包括&#xff1a;使…

Ubuntu 20.04 上安裝 SPDK

以下是在 Ubuntu 20.04 上安裝 SPDK (Storage Performance Development Kit) 的完整步驟&#xff1a;1. 系統準備# 更新系統 sudo apt update sudo apt upgrade -y# 安裝基礎依賴 sudo apt install -y git make gcc g libssl-dev libaio-dev libnuma-dev \pkg-config python3 p…

解決WPS圖片在Excel表格中無法打開

若出現無法打開的情況&#xff0c;還請回到WPS中&#xff0c;點擊圖片&#xff0c;右鍵&#xff1a;轉化為浮動圖片保存&#xff0c;然后便能正常打開&#xff01;

【Ollama】open-webui部署模型

目錄 一、本地部署Ollama 1.1 進入官網復安裝命令 1.2 執行安裝命令 1.3 驗證是否安裝成功 二、啟動Ollama服務 三、運行模型 方法一&#xff1a;拉取模型鏡像 方法二&#xff1a;拉取本地模型 四、使用Open WebUI 部署模型 4.1 創建虛擬環境 4.2 安裝依賴 4.3 運行…