主頁 > 作業系統 > BMP影像的旋轉-C++實作

BMP影像的旋轉-C++實作

2020-10-22 02:05:30 作業系統

最近數字影像處理課要求用C++處理BMP影像,我很無語,有大好的matlab不用,,,,

但是,利用C++去寫的話確實會對原理和codeing水平有些幫助,所以認真寫了,,

實驗環境:windows10+Clion+MinGW64

參考資料:https://blog.csdn.net/qq_36752072/article/details/78151770

本工程所使用的頭檔案:

#include<iostream>
#include <cmath>
#include <windows.h>
#include <stdio.h>

 

1、原理部分:

  要進行BMP影像的處理,那我們首先就要了解BMP圖片的格式,其實主要分為四個部分:

  1、位圖檔案頭資料(BITMAPFILEHEADER):這個資料結構包含了BMP影像檔案的型別、大小等資訊;

typedef struct targetBITMAPFILEHEADER{
    WORD bfType; //檔案型別,對于位圖來說,這一部分為0x4d42
    DWORD bfSize; //檔案大小(包含這14位元組)
    WORD bfReserved1; //保留字,不考慮
    WORD bfReserved2; //保留字,同上
    DWORD bfOffBits; //實際位圖資料的偏移位元組數,即前三個部分長度之和 
}BITMAPFILEHEADER;

  2、位圖資訊頭資料(BITMAPINFOHEADER):這個資料結構則是包含了BMP影像資料的寬、高、壓縮方法、定義顏色、占用空間等等資訊;

typedef struct targetBITMAPINFOHEADER{
    DWORD   biSize;             //指定此結構體的長度,為40  
    LONG    biWidth;            //位圖寬  
    LONG    biHeight;           //位圖高  
    WORD    biPlanes;           //平面數,為1  
    WORD    biBitCount;         //采用顏色位數,可以是1,2,4,8,16,24,新的可以是32  
    DWORD   biCompression;      //壓縮方式,可以是0,1,2,其中0表示不壓縮  
    DWORD   biSizeImage;        //實際位圖資料占用的位元組數  
    LONG    biXPelsPerMeter;    //X方向解析度  
    LONG    biYPelsPerMeter;    //Y方向解析度  
    DWORD   biClrUsed;          //使用的顏色數,如果為0,則表示默認值(2^顏色位數)  
    DWORD   biClrImportant;     //重要顏色數,如果為0,則表示所有顏色都是重要的  
}BITMAPINFOHEADER;

  3、調色板(RGBQUAD):其中,這一部分的資料結構是可選擇的,有些為徒需要調色板,有些位圖則不需要(比如24位的真彩圖就不需要);

//為什么需要調色板呢?
//理由是:可以用調色板對顏色進行映射,從而壓縮儲存空間,
//正常情況下,24bit的位圖每一個像素都有RGB三個通道,一共需要24bit
//但是,一幅圖里可能用不到那么多顏色,比如256級灰度影像,
//此時,只需要用4bit,就可以表示2^8種通過調色板定義的顏色,
typedef struct tagRGBQUAD{
    BYTE rgbBlue;
    BYTE rgbGreen;
    BYTE rgbRed;
    BYTE rgbReserved;        //不用管設為0即可
}RGBQUAD;                

  4、位圖資料:這部分的內容根據BMP位圖使用的位數不同而不同,在24位真彩圖中,直接使用RGB,而其他的小于24位的則使用調色板中顏色的索引值,

typedef struct tagIMAGEDATA  
{  
    BYTE blue;  
    BYTE green;  
    BYTE red;  
}IMAGEDATA;

  接下來我們需要了解的是,如何進行影像旋轉,首先,最重要的是,我們要知道旋轉之后,整個圖片的大小其實是改變了的(以圖片中心旋轉的話),圖片來自《數字影像處理編程入門》,

 

 

  可以明顯地看出,從原來的點到現在的點是一種線性變換,那么我們就可以用矩陣來表示這種運算,然后求逆運算就可以由(x1,y1)求出原來的坐標(x0,y0),這相當于把旋轉后圖上的像素,映射到原圖的像素上,然后把原圖該映射點的資料復制給新圖該點,這樣就完成了圖片的旋轉,

  對于無法映射到原圖的點,我們可以把它們的RGB值設為0,這樣就會顯示成黑色,

  但是像素畢竟不是點,旋轉之后會有誤差,,如果旋轉之后的像素點并不是很如人意的落在像素點上,而是落在臨近的四個像素點構成的正方形區域內(而且這種情況應該是很常見的一種),我們使用雙線性插值法來估計該點像素值,

 

 

 

代碼部分:

  

/**
  *注意,由于包含了頭檔案<windows.h>,所以檔案頭和資訊頭還有調色板的定義都用不到
*/
void rotateBMP(string path, string resPath, int angle) {
    //獲取路徑名
    const char *picture_name=path.c_str();
    const char *res_name=resPath.c_str();
    //定義檔案指標
    FILE *file, *targetFile;
    //定義檔案頭和資訊頭
    BITMAPFILEHEADER bmpFile, writeBmpFile;
    BITMAPINFOHEADER bmpInfo, writeBmpInfo;
    //角度轉弧度
    auto thelta=(double)(angle*PI/180);
    auto cosa=(float)cos((double)thelta);
    auto sina=(float)sin((double)thelta);
    file = fopen(picture_name, "rb");
    targetFile=fopen(res_name,"wb");
    fread(&bmpFile, sizeof(BITMAPFILEHEADER), 1, file);
    fseek(file, sizeof(BITMAPFILEHEADER), 0);//跳過位圖檔案頭結構
    fread(&bmpInfo, sizeof(BITMAPINFOHEADER), 1, file);
//    //fseek(file,sizeof(BITMAPINFOHEADER),0);//跳過資訊頭
    this->ShowBMPHead(bmpFile);
    this->ShowBMPInfoHead(bmpInfo);
    /**
     step 1 : 圖片處理第一步,首先是完成將檔案頭,資訊頭等的資料遷移
    **/
    writeBmpFile = bmpFile;
    writeBmpInfo = bmpInfo;
    int width = bmpInfo.biWidth;
    int height = bmpInfo.biHeight;
    cout<<width<<","<<height<<endl;
    //原圖的四個角坐標
    auto SrcX1=(float)(-0.5*width);
    auto SrcY1=(float)(0.5*height);
    auto SrcX2=(float)(0.5*width);
    auto SrcY2=(float)(0.5*height);
    auto SrcX3=(float)(-0.5*width);
    auto SrcY3=(float)(-0.5*height);
    auto SrcX4=(float)(0.5*width);
    auto SrcY4=(float)(-0.5*height);
    //新圖的四個角坐標
    float DstX1=cosa*SrcX1+sina*SrcY1;
    float DstY1=-sina*SrcX1+cosa*SrcY1;
    float DstX2=cosa*SrcX2+sina*SrcY2;
    float DstY2=-sina*SrcX2+cosa*SrcY2;
    float DstX3=cosa*SrcX3+sina*SrcY3;
    float DstY3=-sina*SrcX3+cosa*SrcY3;
    float DstX4=cosa*SrcX4+sina*SrcY4;
    float DstY4=-sina*SrcX4+cosa*SrcY4;
    //計算新圖的寬度和高度
    auto newWidth=(int)(max(fabs(DstX4-DstX1),fabs(DstX3-DstX2))+0.5);
    auto newHeight=(int)(max(fabs(DstY4-DstY1),fabs(DstY3-DstY2))+0.5);
    writeBmpInfo.biWidth = newWidth;
    writeBmpInfo.biHeight = newHeight;
    // 在計算實際占用的空間的時候我們需要將寬度為4byte的倍數
    int writewidth = WIDTHBYTES(newWidth * writeBmpInfo.biBitCount);
    writeBmpInfo.biSizeImage = writewidth * writeBmpInfo.biHeight;
    writeBmpFile.bfSize = 54 + writeBmpInfo.biSizeImage;
    //把修改過的檔案頭和資訊頭寫入目標檔案
    fwrite(&writeBmpFile, 1, sizeof(BITMAPFILEHEADER), targetFile);
    fwrite(&writeBmpInfo, 1, sizeof(BITMAPINFOHEADER), targetFile);
    //申請空間
    if(bmpInfo.biBitCount==24)//如果是24位的BMP圖
    {
        int l_width=WIDTHBYTES(width * bmpInfo.biBitCount);
        BYTE *preData = https://www.cnblogs.com/xjknb/p/(BYTE *)malloc(height * l_width);
        memset(preData, 0, height * l_width);
        BYTE *aftData = https://www.cnblogs.com/xjknb/p/(BYTE *)malloc(newHeight * writewidth);
        memset(aftData, 0, newHeight * writewidth);
        //原來的旋轉中心
        int rotateX = width / 2;
        int rotateY = height / 2;
        //新圖的中心
        int write_rotateX = newWidth / 2;
        int write_rotateY = newHeight / 2;
        int OriginalImg = l_width * height;
        int LaterImg = writewidth * newHeight;
        fread(preData, 1, OriginalImg, file);
        for (int i = 0; i < newHeight; ++i) {
            for (int j = 0; j < newWidth; ++j) {
                int index = i * writewidth + j * 3;
                // 利用公式計算這個原來的點的地方
                double y0 =
                        (j - write_rotateX) * sina + (i - write_rotateY) * cosa + rotateY;
                double x0 =
                        (j - write_rotateX) * cosa - (i - write_rotateY) * sina + rotateX;
                if((x0>=0)&&(x0<width)&&(y0>=0)&&(y0<=height))
                {
                    /**
                     * 我們在這里使用雙線性插值法來完成對應
                    */
                    int y0_True = y0;
                    int x0_True = x0;
                    double distance_to_a_X = x0 - x0_True;
                    double distance_to_a_Y = y0 - y0_True;

                    int original_point_A = y0_True * l_width + x0_True * 3;
                    int original_point_B = y0_True * l_width + (x0_True + 1) * 3;
                    int original_point_C = (y0_True + 1) * l_width + x0_True * 3;
                    int original_point_D = (y0_True + 1) * l_width + (x0_True + 1) * 3;

                    if (x0_True == width - 1) {
                        original_point_A = original_point_B;
                        original_point_C = original_point_D;
                    }
                    if (y0_True == height - 1) {
                        original_point_C = original_point_A;
                        original_point_D = original_point_B;
                    }
                    //相當于blue
                    aftData[index] = (1 - distance_to_a_X) * (1 - distance_to_a_Y) * preData[original_point_A]
                                     + (1 - distance_to_a_X) * distance_to_a_Y * preData[original_point_B]
                                     + distance_to_a_X * (1 - distance_to_a_Y) * preData[original_point_C]
                                     + distance_to_a_X * distance_to_a_Y * preData[original_point_D];
                    //相當于green
                    aftData[index + 1] = (1 - distance_to_a_X) * (1 - distance_to_a_Y) * preData[original_point_A + 1]
                                         + (1 - distance_to_a_X) * distance_to_a_Y * preData[original_point_B + 1]
                                         + distance_to_a_X * (1 - distance_to_a_Y) * preData[original_point_C + 1]
                                         + distance_to_a_X * distance_to_a_Y * preData[original_point_D + 1];
                    //相當于red
                    aftData[index + 2] = (1 - distance_to_a_X) * (1 - distance_to_a_Y) * preData[original_point_A + 2]
                                         + (1 - distance_to_a_X) * distance_to_a_Y * preData[original_point_B + 2]
                                         + distance_to_a_X * (1 - distance_to_a_Y) * preData[original_point_C + 2]
                                         + distance_to_a_X * distance_to_a_Y * preData[original_point_D + 2];
                }
            }
        }
        fwrite(aftData,1,LaterImg,targetFile);
        fclose(file);
        fclose(targetFile);
        delete [] preData;
        delete [] aftData;
    }
    else if(bmpInfo.biBitCount==8)//如果是8位的BMP圖
    {
        RGBQUAD strPla[256];//復制調色板
        for (unsigned int nCounti = 0; nCounti < 256; nCounti++) {
            fread((char *)&(strPla[nCounti].rgbBlue), 1, sizeof(BYTE), file);
            fread((char *)&(strPla[nCounti].rgbGreen), 1, sizeof(BYTE), file);
            fread((char *)&(strPla[nCounti].rgbRed), 1, sizeof(BYTE), file);
            fread((char *)&(strPla[nCounti].rgbReserved), 1, sizeof(BYTE), file);
        }
        //寫入調色板
        for (int nCounti = 0; nCounti < 256; nCounti++) {
            fwrite((char *)&(strPla[nCounti].rgbBlue), 1, sizeof(BYTE), targetFile);
            fwrite((char *)&(strPla[nCounti].rgbGreen), 1, sizeof(BYTE), targetFile);
            fwrite((char *)&(strPla[nCounti].rgbRed), 1, sizeof(BYTE), targetFile);
            fwrite((char *)&(strPla[nCounti].rgbReserved), 1, sizeof(BYTE), targetFile);
        }
        int l_width=WIDTHBYTES(width * bmpInfo.biBitCount);
        BYTE *preData = https://www.cnblogs.com/xjknb/p/(BYTE *)malloc(height * l_width);
        memset(preData, 0, height * l_width);
        BYTE *aftData = https://www.cnblogs.com/xjknb/p/(BYTE *)malloc(newHeight * writewidth);
        memset(aftData, 0, newHeight * writewidth);
        //讀取原影像素資料
        fread(preData, sizeof(GRAYDATA)*width, height, file);
        //初始化新圖的像素點
        for (int i = 0; i < newHeight; ++i) {
            for (int j = 0; j < newWidth; ++j) {
                *(aftData+i*newWidth+j)=0;
            }
        }
        int rotateX = width / 2;
        int rotateY = height / 2;
        //新圖的中心
        int write_rotateX = newWidth / 2;
        int write_rotateY = newHeight / 2;
        int OriginalImg = l_width * height;
        int LaterImg = writewidth * newHeight;
        fread(preData, 1, OriginalImg, file);
        for (int i = 0; i < newHeight; ++i) {
            for (int j = 0; j < newWidth; ++j) {
                int index = i * writewidth + j ;
                // 利用公式計算這個原來的點的地方
                double y0 =
                        (j - write_rotateX) * sina + (i - write_rotateY) * cosa + rotateY;
                double x0 =
                        (j - write_rotateX) * cosa - (i - write_rotateY) * sina + rotateX;
                if((x0>=0)&&(x0<width)&&(y0>=0)&&(y0<=height))
                {
                    /**
                     * 我們在這里使用雙線性插值法來完成對應
                    */
                    int y0_True = y0;
                    int x0_True = x0;
                    double distance_to_a_X = x0 - x0_True;
                    double distance_to_a_Y = y0 - y0_True;

                    int original_point_A = y0_True * l_width + x0_True ;
                    int original_point_B = y0_True * l_width + (x0_True + 1) ;
                    int original_point_C = (y0_True + 1) * l_width + x0_True ;
                    int original_point_D = (y0_True + 1) * l_width + (x0_True + 1) ;

                    if (x0_True == width - 1) {
                        original_point_A = original_point_B;
                        original_point_C = original_point_D;
                    }
                    if (y0_True == height - 1) {
                        original_point_C = original_point_A;
                        original_point_D = original_point_B;
                    }
                    //相當于blue
                    aftData[index] = (1 - distance_to_a_X) * (1 - distance_to_a_Y) * preData[original_point_A]
                                     + (1 - distance_to_a_X) * distance_to_a_Y * preData[original_point_B]
                                     + distance_to_a_X * (1 - distance_to_a_Y) * preData[original_point_C]
                                     + distance_to_a_X * distance_to_a_Y * preData[original_point_D];
                }
            }
        }
        fwrite(aftData,1,LaterImg,targetFile);
        fclose(file);
        fclose(targetFile);
        delete [] preData;
        delete [] aftData;
    }
    else
    {
        cout<<"錯誤的輸入!!!!!!!!!!!!!"<<endl;
    }
}

 



 

轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/184891.html

標籤:Windows

上一篇:shell腳本變數拼接出錯

下一篇:BMP影像的旋轉-C++實作

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • CA和證書

    1、在 CentOS7 中使用 gpg 創建 RSA 非對稱密鑰對 gpg --gen-key #Centos上生成公鑰/密鑰對(存放在家目錄.gnupg/) 2、將 CentOS7 匯出的公鑰,拷貝到 CentOS8 中,在 CentOS8 中使用 CentOS7 的公鑰加密一個檔案 gpg -a ......

    uj5u.com 2020-09-10 00:09:53 more
  • Kubernetes K8S之資源控制器Job和CronJob詳解

    Kubernetes的資源控制器Job和CronJob詳解與示例 ......

    uj5u.com 2020-09-10 00:10:45 more
  • VMware下安裝CentOS

    VMware下安裝CentOS 一、軟硬體準備 1 Centos鏡像準備 1.1 CentOS鏡像下載地址 下載地址 1.2 CentOS鏡像下載程序 點擊下載地址進入如下圖的網站,選擇需要下載的版本,這里選擇的是Centos8,點擊如圖所示。 決定選擇Centos8后,選擇想要的鏡像源進行下載,此 ......

    uj5u.com 2020-09-10 00:12:10 more
  • 如何使用Grep命令查找多個字串

    如何使用Grep 命令查找多個字串 大家好,我是良許! 今天向大家介紹一個非常有用的技巧,那就是使用 grep 命令查找多個字串。 簡單介紹一下,grep 命令可以理解為是一個功能強大的命令列工具,可以用它在一個或多個輸入檔案中搜索與正則運算式相匹配的文本,然后再將每個匹配的文本用標準輸出的格式 ......

    uj5u.com 2020-09-10 00:12:28 more
  • git配置http代理

    git配置http代理 經常遇到克隆 github 慢的問題,這里記錄一下幾種配置 git 代理的方法,解決 clone github 過慢。 目錄 git配置代理 git單獨配置github代理 git配置全域代理 配置終端環境變數 git配置代理 主要使用 git config 命令 git單獨 ......

    uj5u.com 2020-09-10 00:12:33 more
  • Linux npm install 裝包時提示Error EACCES permission denied解

    npm install 裝包時提示Error EACCES permission denied解決辦法 ......

    uj5u.com 2020-09-10 00:12:53 more
  • Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包

    Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包。 18 (flaskApi) [root@67 flaskDemo]# yum -y install nginx 19 已加載插件:fastestmirror, langpacks 20 Loading ......

    uj5u.com 2020-09-10 00:13:13 more
  • Linux查看服務器暴力破解ssh IP

    在公網的服務器上經常遇到別人爆破你服務器的22埠,用來挖礦或者干其他嘿嘿嘿的事情~ 這種情況下正確的做法是: 修改默認ssh的22埠 使用設定密鑰登錄或者白名單ip登錄 建議服務器密碼為復雜密碼 創建普通用戶登錄服務器(root權限過大) 建立堡壘機,實作統一管理服務器 統計爆破IP [root ......

    uj5u.com 2020-09-10 00:13:17 more
  • CentOS 7系統常見快捷鍵操作方式

    Linux系統中一些常見的快捷方式,可有效提高操作效率,在某些時刻也能避免操作失誤帶來的問題。 ......

    uj5u.com 2020-09-10 00:13:31 more
  • CentOS 7作業系統目錄結構介紹

    作業系統存在著大量的資料檔案資訊,相應檔案資訊會存在于系統相應目錄中,為了更好的管理資料資訊,會將系統進行一些目錄規劃,不同目錄存放不同的資源。 ......

    uj5u.com 2020-09-10 00:13:35 more
最新发布
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:43:21 more
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:42:36 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:26:53 more
  • 設定Windows主機的瀏覽器為wls2的默認瀏覽器

    這里以Chrome為例。 1. 準備作業 wsl是可以使用Windows主機上安裝的exe程式,出于安全考慮,默認情況下改功能是無法使用。要使用的話,終端需要以管理員權限啟動。 我這里以Windows Terminal為例,介紹如何默認使用管理員權限打開終端,具體操作如下圖所示: 2. 操作 wsl ......

    uj5u.com 2023-04-19 09:25:49 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:19:04 more
  • Linux學習筆記

    IP地址和主機名 IP地址 ifconfig可以用來查詢本機的IP地址,如果不能使用,可以通過install net-tools安裝。 Centos系統下ens33表示主網卡;inet后表示IP地址;lo表示本地回環網卡; 127.0.0.1表示代指本機;0.0.0.0可以用于代指本機,同時在放行設 ......

    uj5u.com 2023-04-18 06:52:01 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:50 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:01 more
  • 你是不是暴露了?

    作者:袁首京 原創文章,轉載時請保留此宣告,并給出原文連接。 如果您是計算機相關從業人員,那么應該經歷不止一次網路安全專項檢查了,你肯定是收到過資訊系統技術檢測報告,要求你加強風險監測,確保你提供的系統服務堅實可靠了。 沒檢測到問題還好,檢測到問題的話,有些處理起來還是挺麻煩的,尤其是線上正在運行的 ......

    uj5u.com 2023-04-05 16:52:56 more
  • 細節拉滿,80 張圖帶你一步一步推演 slab 記憶體池的設計與實作

    1. 前文回顧 在之前的幾篇記憶體管理系列文章中,筆者帶大家從宏觀角度完整地梳理了一遍 Linux 記憶體分配的整個鏈路,本文的主題依然是記憶體分配,這一次我們會從微觀的角度來探秘一下 Linux 內核中用于零散小記憶體塊分配的記憶體池 —— slab 分配器。 在本小節中,筆者還是按照以往的風格先帶大家簡單 ......

    uj5u.com 2023-04-05 16:44:11 more