首頁 資料庫 mysql教程 PostgreSQL 堆分配器mmgr详解

PostgreSQL 堆分配器mmgr详解

Jun 07, 2016 pm 05:20 PM

mmgr是postgresql的内存管理模块,其代码分布在aset.c, mctx.c和portalmem.c这三个文件之中。这里主要分析它的堆内存的管理机制,

mmgr是postgresql的内存管理模块,其代码分布在aset.c, mctx.c和portalmem.c这三个文件之中。这里主要分析它的堆内存的管理机制,也就是aset.c文件中的内容。

AllocSetContext是堆内存管理的主要结构,其定义如下:

typedef struct AllocSetContext { AllocBlock blocks; AllocChunk freelist[ALLOCSET_NUM_FREELISTS]; Size initBlockSize; Size maxBlockSize; Size nextBlockSize; Size allocChunkLimit; AllocBlock keeper; } AllocSetContext;

其中的成员可以分为三个部分,我用三种不同的颜色标记了出来:

1) 黄色部分是AllocSetContext的头部,如果用面向对象的观点来看,可以说AllocSetContext是继承自MemoryContextData的,这里我们不关心MemoryContextData的定义,它提供了对AllocSetContext更高层次的管理。

2)粉色部分是一些配置参数。

3) 紫色部分是我们这篇博客的主角。blocks和freelist对应于堆内存管理的两个方面。下面详细描述。

AllocSetContext作为malloc/free与更上层应用的中间层,向下需要管理使用malloc从操作系统申请到的内存,对上则需要提供内存的获取与释放的接口。我们先说第一个方面,也就是它是如何管理malloc来的内存的。

AllocSetContext将从操作系统中申请到的内存放在一下链表中进行管理,这个链表就是紫色部分的blocks。blocks中的每一项的结构叫做AllocBlockData,它的定义如下:

typedef
   
   

AllocBlockData是向操作系统申请和释放内存的基本单位,为了简便起见,下面就直接叫它Block了。在接收到内存分配请求的时候,AllocSetContext如果发现blocks头部的那个Block没有足够的空间,就再从操作系统中申请一个更大的Block作为blocks的头。以后的分配出的内存就是从这个更大的Block上割出来的。这个更大是多大呢,pg将它设为前一个的2倍,也就是说blocks这个链表从尾部到头部,每向前一个Block的大小就会增长一倍。这里说的是通常情况,也会有非通常情况的,比如这个Block是不可能无限制地增大的,它有一个最大的可以分配的大小AllocSetContext::maxBlockSize,也还有来自其它方面的限制,要了解这个限制就得先说一说 AllocSetContext的另外一个主要功能了--对外提供获取内存和释放内存的接口。

      AllocSetContext提供给外部使用的主要接口为:

static void *AllocSetAlloc(MemoryContext context, Size size);

static void AllocSetFree(MemoryContext context, void *pointer);

static void *AllocSetRealloc(MemoryContext context, void *pointer, Size size);

  你可以调用AllocSetAlloc(cxt,sizeof(XX)) 来获得一块可用的特定大小的内存,但是如果你天真地以为你需要的是15个字节的空间,它就会精确地给你15个字节,你就错了,实际上,为了你的这次内在请求,它给了你16个字节的空间,外加一个信息头。也就是说它给你返回的内存有统一的结构,大小也有特定地限制。

      这个统一的内存结构的定义如下:

typedef struct AllocChunkData

{

    /* aset is the owning aset if allocated, or the freelist link if free */

    void       *aset;

    /* size is always the size of the usable space in the chunk */

    Size        size;

#ifdef MEMORY_CONTEXT_CHECKING

    /* when debugging memory usage, also store actual requested size */

    /* this is zero in a free chunk */

    Size        requested_size;

#endif

}   AllocChunkData;

   AllocChunkData是返回内存的基本单位,,下面叫它Chunk。如果你申请到一个大小为16字节的内存,你实际拿到是像下图的这么个东西,返回给你的地址前面是有一个Chunk头的:

       为了加快分配的速度和方便管理,每个Chunk里的可用空间都是2的整数次幂。同时还维护了一个叫做freelist的数组,这个数组的每一项都是一个Chunk的队列,每个队列内的Chunk大小都是一样的。下面是某时刻free list的内存布局图:

       这个free list的Chunk的来源有两个方面:

       1) 调用AllocSetFree回收来的Chunk;

       2) 调用AllocSetAlloc时,如果发现blocks链表的第一个Block没有足够的空间,这时候会分配一个更大的Block,但是在做这样事之前,首先要将头上那个Block中还剩下的空间酌情格式化为一些Chunk加入到free list这中。

       由于这个free list数组的大小是固定的,所以在free list之中最大的Chunk的可用空间也是有限的,如果申请比最大的Chunk所能提供的空间还要大的内存时,就会被认为这是在申请一块大内存,会直接从操作系统中malloc出来给你,这种内存对这个堆管理器来说只是个过客,free时是不会加入到free list中的,也就是说这种不会被堆管理器直接重利用。

 

       好了, 堆内存的管理的基本结构数据结构就介绍这么多,是时候看看几个主要方法的实现了,这里只说一下几个最常用 的接口: AllocSetAlloc , AllocSetFree, AllocSetRealloc

         

       下面这个图解释了AllocSetAlloc的流程:

      1) 首先判断是不是在申请大内存?如果是转入2),否则转入3);

      2) 直接malloc出大小为: size 加上Block和Chunk头的大小,调整好指针位置,返回;

      3) 计算出实际分配的内存大小,这个大小是比size大的最小的2^k;

      4)  free list中是否有这种大小的Chunk? 若有转入5),否则转入6);

      5)  从free list中取出一个满足条件的Chunk, 返回;

      6) blocks链表的第一个Block是不是足够的空间,若有转入9),否则继续

      7) 将第一个Block中剩余的空间格式化为一些Chunk,加入到free list中;

      8) malloc出一个更大的Block,加入到blocks中,

      9) 从Block中格式化一个满足条件的Chunk,返回。

 

      AllocSetFree的操作比较的简单,如下图,其步骤为:

       1) 根据传入的指针算出Chunk头的位置 ( p - sizeof(AllocChunkData));

       2) 根据Chunk中的size信息判断是不是大内存,若不是,转入4),否则继续;

       3) 直接free掉(是个过客,不再利用)返回。

       4) 将Chunk入到合适的free list之中。

 

       AllocSetRealloc的步骤如下:

         1)  调整指针p的位置得到Chunk头的地址;

         2)  如果再分配的大小比Chunk的要小,直接返回; 

         3) 如果是大内存,则直接调用realloc分配一个更大的Block,并更新blocks中对应的项(所有的Block在使用期间都被blocks管理着), 然后返回.

         4) 否则则先调用 AllocSetFree,再调用 AllocSetAlloc.

 

       这个堆管理器的最主要的功能和实现就叙述完了,最后看一下它提供的更高级的一些调试功能:

       1) CLOBBER_FREED_MEMORY   野指针对任何一个C/C++程序员来说都是豺狼虎豹,如果定义了这个宏,在面对野指针的时候你会从容不少,因为这个宏启用了一项功能:AllocSetFree的内存都会被置为0x7f, 这样在你第一次使用野指针的时候就会立马发现它。

       2) MEMORY_CONTEXT_CHECKING  由于在大多数情况下,mmgr返回的内存大小大于申请大小的最小的2次幂。所以内存或多或少总是有浪费的。但这也是提高内存分配所带来必然的损失,为了心理平衡一下,我们可以利用这多出来的内存,做其他的事,比如这个宏就会启用这样一项功能:在实际大小后面填充一0x7e,这样就可以检测是否有内存越界的事情发生了。

linux

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1666
14
CakePHP 教程
1425
52
Laravel 教程
1325
25
PHP教程
1272
29
C# 教程
1252
24
MySQL的角色:Web應用程序中的數據庫 MySQL的角色:Web應用程序中的數據庫 Apr 17, 2025 am 12:23 AM

MySQL在Web應用中的主要作用是存儲和管理數據。 1.MySQL高效處理用戶信息、產品目錄和交易記錄等數據。 2.通過SQL查詢,開發者能從數據庫提取信息生成動態內容。 3.MySQL基於客戶端-服務器模型工作,確保查詢速度可接受。

說明InnoDB重做日誌和撤消日誌的作用。 說明InnoDB重做日誌和撤消日誌的作用。 Apr 15, 2025 am 12:16 AM

InnoDB使用redologs和undologs確保數據一致性和可靠性。 1.redologs記錄數據頁修改,確保崩潰恢復和事務持久性。 2.undologs記錄數據原始值,支持事務回滾和MVCC。

MySQL:世界上最受歡迎的數據庫的簡介 MySQL:世界上最受歡迎的數據庫的簡介 Apr 12, 2025 am 12:18 AM

MySQL是一種開源的關係型數據庫管理系統,主要用於快速、可靠地存儲和檢索數據。其工作原理包括客戶端請求、查詢解析、執行查詢和返回結果。使用示例包括創建表、插入和查詢數據,以及高級功能如JOIN操作。常見錯誤涉及SQL語法、數據類型和權限問題,優化建議包括使用索引、優化查詢和分錶分區。

MySQL的位置:數據庫和編程 MySQL的位置:數據庫和編程 Apr 13, 2025 am 12:18 AM

MySQL在數據庫和編程中的地位非常重要,它是一個開源的關係型數據庫管理系統,廣泛應用於各種應用場景。 1)MySQL提供高效的數據存儲、組織和檢索功能,支持Web、移動和企業級系統。 2)它使用客戶端-服務器架構,支持多種存儲引擎和索引優化。 3)基本用法包括創建表和插入數據,高級用法涉及多表JOIN和復雜查詢。 4)常見問題如SQL語法錯誤和性能問題可以通過EXPLAIN命令和慢查詢日誌調試。 5)性能優化方法包括合理使用索引、優化查詢和使用緩存,最佳實踐包括使用事務和PreparedStatemen

為什麼要使用mysql?利益和優勢 為什麼要使用mysql?利益和優勢 Apr 12, 2025 am 12:17 AM

選擇MySQL的原因是其性能、可靠性、易用性和社區支持。 1.MySQL提供高效的數據存儲和檢索功能,支持多種數據類型和高級查詢操作。 2.採用客戶端-服務器架構和多種存儲引擎,支持事務和查詢優化。 3.易於使用,支持多種操作系統和編程語言。 4.擁有強大的社區支持,提供豐富的資源和解決方案。

MySQL與其他編程語言:一種比較 MySQL與其他編程語言:一種比較 Apr 19, 2025 am 12:22 AM

MySQL与其他编程语言相比,主要用于存储和管理数据,而其他语言如Python、Java、C 则用于逻辑处理和应用开发。MySQL以其高性能、可扩展性和跨平台支持著称,适合数据管理需求,而其他语言在各自领域如数据分析、企业应用和系统编程中各有优势。

MySQL:從小型企業到大型企業 MySQL:從小型企業到大型企業 Apr 13, 2025 am 12:17 AM

MySQL適合小型和大型企業。 1)小型企業可使用MySQL進行基本數據管理,如存儲客戶信息。 2)大型企業可利用MySQL處理海量數據和復雜業務邏輯,優化查詢性能和事務處理。

MySQL索引基數如何影響查詢性能? MySQL索引基數如何影響查詢性能? Apr 14, 2025 am 12:18 AM

MySQL索引基数对查询性能有显著影响:1.高基数索引能更有效地缩小数据范围,提高查询效率;2.低基数索引可能导致全表扫描,降低查询性能;3.在联合索引中,应将高基数列放在前面以优化查询。

See all articles