`

pg启动过程中的那些事一:初始化TopMemoryContext和ErrorContext

阅读更多

1先上个示意图,看一下函数调用过程梗概,中间略过部分细节

 



 

             前面标1的是初始化TopMemoryContext

             前面标2的是初始化ErrorContext

初始化TopMemoryContextErrorContext的方法调用流程图

 

2初始化TopMemoryContext的过程

 

 

话说main()->->PostmasterMain()->->MemoryContextInit()->AllocSetContextCreate()以后用“-> 表示调用AllocSetContextCreate()函数主要是初始化AllocSet类型的变量,AllocSet的类型是“AllocSetContext*”,AllocSetContext是结构,定义见下面,也就是说,AllocSetContextCreate()函数主要是初始化AllocSetContext类型的变量。

MemoryContextInit()函数中,一上来就是下面这句,调用AllocSetContextCreate初始化TopMemoryContext

 

     TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,

                                                    "TopMemoryContext",

                                                    0,

                                                    8 * 1024,

                                                    8 * 1024);

TopMemoryContext是个全局变量,定义如下

MemoryContext TopMemoryContext = NULL;

     

MemoryContextInit()函数调用过来初始化Memorycontext类型的全局变量TopMemoryContext,不是AllocSetContextCreate()函数主要是初始化AllocSetContext类型的变量吗,怎么又初始化上Memorycontext类型的全局变量TopMemoryContext了呢,先卖个关子,容后再说。这是PostgresSQL(以后简称pg)一个比较秒的地方,也涉及了后面用到的面向过程编程的一个技巧。

TopMemoryContext这个全局变量在pg有至关重要,统领全局的地位,以后自然明白。

 

AllocSetContext定义如下:

typedef struct AllocSetContext

{

         MemoryContextData header;  /* Standard memory-context fields */

         /* Info about storage allocated in this context: */

         AllocBlock blocks;                         /* head of list of blocks in this set */

         AllocChunk        freelist[ALLOCSET_NUM_FREELISTS];             /* free chunk lists */

         bool           isReset;               /* T = no space alloced since last reset */

         /* Allocation parameters for this context: */

         Size            initBlockSize;      /* initial block size */

         Size            maxBlockSize;   /* maximum block size */

         Size            nextBlockSize;   /* next block size to allocate */

         AllocBlock keeper;                        /* if not NULL, keep this block over resets */

} AllocSetContext;

 

 

AllocSetContext中有三个变量的类型分别是MemoryContextDataAllocBlockAllocChunk,这些类型是pg管理AllocSetMemoryContext涉及内存机制的主要元素,搭起pg管理AllocSetMemoryContext涉及的内存的架构,后面会逐个提到。

 

AllocSetContextCreate()函数中,刚声明一个AllocSet类型的变量conext,马上就调用MemoryContextCreate()函数,代码见下。MemoryContextCreate()函数从名字就能看出来是创建MemoryContext的,创建一个MemoryContext类型的值后返回,返回后做了类型强制转换为AllocSet赋给context。调用MemoryContextCreate()函数创建MemoryContext时传的第二个参数是要创建类型的大小,这里取的就是AllocSetContext的大小,而不是MemoryContext的大小。

 

     AllocSet context;

     context = (AllocSet) MemoryContextCreate(T_AllocSetContext,

                                                    sizeof(AllocSetContext),

                                                    &AllocSetMethods,

                                                    parent,

                                                    name);

 

 

MemoryContextCreate()函数主要是初始化MemoryContextMemoryContext的类型是“MemoryContextData *”,MemoryContextData是个结构,定义见下面。

 

typedef struct MemoryContextData

{

         NodeTag           type;                            /* identifies exact kind of context */

         MemoryContextMethods *methods;                   /* virtual function table */

         MemoryContext parent;            /* NULL if no parent (toplevel context) */

         MemoryContext firstchild; /* head of linked list of children */

         MemoryContext nextchild;        /* next child of same parent */

         char    *name;                            /* context name (just for debugging) */

} MemoryContextData;

 

MemoryContextCreate()函数的简化代码如下,主要是声明一个MemoryContext类型的局部变量node,分配内存并初始化。注意,这时还没有初始化TopMemoryContext,所以node的内存空间是malloc出来的。MemoryContext类型的局部变量node初始化完后返回。

 

MemoryContext

MemoryContextCreate(NodeTag tag, Size size,

                       MemoryContextMethods *methods,

                       MemoryContext parent,

                       const char *name)

{

     MemoryContext node;

     Size     needed = size + strlen(name) + 1;

     if (TopMemoryContext == NULL)

     {

         /* Special case for startup: use good ol' malloc */

         node = (MemoryContext) malloc(needed);

         Assert(node != NULL);

     }

 

     /* Initialize the node as best we can */

     MemSet(node, 0, size);

     node->type = tag;

     node->methods = methods;

     node->parent = NULL;        /* for the moment */

     node->firstchild = NULL;

     node->nextchild = NULL;

     node->name = ((char *) node) + size;

     strcpy(node->name, name);

     /* Return to type-specific creation routine to finish up */

     return node;

}

 

 

 

 

AllocSetContextCreate()函数得到从MemoryContextCreate()函数返回的MemoryContextCreate类型的值后转换为AllocSet类型,赋给context,把context其他属性初始化。最后又把context的类型由AllocSet转换为MemoryContext后返回给调用方法,赋值给TopMemoryContext。至此TopMemoryContext初始化完成。

代码见下面。

 

 

 

MemoryContext

AllocSetContextCreate(MemoryContext parent,

         const char *name,

         Size minContextSize,

         Size initBlockSize,

         Size maxBlockSize)

{

     AllocSet context;

     /* Do the type-independent part of context creation */

     context = (AllocSet) MemoryContextCreate(T_AllocSetContext,

                                                    sizeof(AllocSetContext),

                                                    &AllocSetMethods,

                                                    parent,

                                                    name);

 

     context->initBlockSize = initBlockSize;

     context->maxBlockSize = maxBlockSize;

     context->nextBlockSize = initBlockSize;

     context->isReset = true;

     return (MemoryContext) context;

}

 

在初始化TomMemoryContext的过程中,先按AllocSet的类型初始化一个MemoryContext类型的变量,然后把这个变量转成AllocSet类型,初始化AllocSet类型的其它成员,再将其转成MemoryContext类型的变量后赋值给TopMemoryContext。为什么能做这两次类型转换呢?见下面分解。

下面上个图看看初始化出来的TopMemoryContext的结构图(以后所有内存结构图都是低地址在下面,高地址在上面,再后面有内存结构图时就不标低地址位了):

 

 



 


 

TopMemoryContext的内存结构图

 

TopMemoryContext转成AllocSet类型后的内存结构图

 

 

上图中分两块说,先看左边的大方块。其中下面深蓝色部分是MemoryContextData的内存结构,深蓝色和上面的浅颜色部分合起来是AllocSetContext的内存结构。

       初始化TopMemoryContext的时候,分配的内存大小不是按MemoryContextData结构的大小分的,是按AllocSetContext的大小分的内存,又在紧挨着上面分配了17个字节记录这个MemoryContextData /AllocSetContext 的名字“TopMemoryContext”。

       能在初始化TopMemoryContext的过程中能在类型MemoryContextData AllocSetContext之间相互转化,是利用了AllocSetContext结构布局上的特点,刚一开始就是个MemoryContextData,接着是其它成员,这样要是把TopMemoryContextMemoryContextData类型处理,就是上面那个图,图中黑色部分相当于未知,不用管它,剩下的就是MemoryContextData类型,当TopMemoryContextAllocSetContext类型时,就面的图,它就是个AllocSetContext类型的变量了。这样做的好处是在一个结构里既能管理内存空间,又能管理内存空间里的内容,而且逻辑功能划分很清晰。

哦,有人说从中看出了面向对象编程中继承的影子,嗯、啊,是有点,如果MemoryContextData是父类,AllocSetContextMemoryContextData的子类,看起来是挺像的,从内存布局上看子类里也少了指向vitual table member function /viturl member function pointervptr)。看来从面向对象编程到面向过程编程是技术的渐进,就像设备的升级改造。扯的有点远了,打住。

       再看上图的右边,就是上面提到的vitual table,这个是调用MemoryContextCreate()传进去的第三个参数AllocSetMethods,这是一个MemoryContextMethods类型的静态全局变量, 根据这个变量的定义(在下面)就可以看出这是一个为AllocSet Context管理内存的虚拟函数的表(vitual function table),MemoryContextMethods结构里定义了这些函数原型。这些函数实现了pg对内存的管理,整个就是pgAllocSetMemoryContext的内存空间管理机制。

 

 

静态全局变量AllocSetMethods的定义:

static MemoryContextMethods AllocSetMethods = {

     AllocSetAlloc,

     AllocSetFree,

     AllocSetRealloc,

     AllocSetInit,

     AllocSetReset,

     AllocSetDelete,

     AllocSetGetChunkSpace,

     AllocSetIsEmpty,

     AllocSetStats,

#ifdef MEMORY_CONTEXT_CHECKING

     ,AllocSetCheck

#endif

};

结构MemoryContextMethods的定义:

typedef struct MemoryContextMethods

{

     void    *(*alloc) (MemoryContext context, Size size);

     /* call this free_p in case someone #define's free() */

     void     (*free_p) (MemoryContext context, void *pointer);

     void    *(*realloc) (MemoryContext context, void *pointer, Size size);

     void     (*init) (MemoryContext context);

     void     (*reset) (MemoryContext context);

     void     (*delete) (MemoryContext context);

     Size     (*get_chunk_space) (MemoryContext context, void *pointer);

     bool     (*is_empty) (MemoryContext context);

     void     (*stats) (MemoryContext context);

#ifdef MEMORY_CONTEXT_CHECKING

     void     (*check) (MemoryContext context);

#endif

} MemoryContextMethods;

pg中使用这些函数的情况来看,这些方法在MemoryContext中定义,在AllocSet中实现和使用,又像子类实现父类的虚拟方法,又是面向对象编程的影子。面向过程编程中的编程技巧在面向对象编程中基本上都成了编程语言的内在机制了。台湾的侯捷先生说要写一本《c语言高级编程》的书也有十来年了吧,到现在都没出,是否有这个原因呢

至此,TopMemoryContext初始化完成了,里面的其他属性就不写了。有了前面内容垫底,初始化ErrorContext就好写多了,因为它的类型和TomMemoryContext是一样的。

 

 

 

 

3 初始化ErrorContext的过程

       先看看MemoryContextInit()的代码,这个很简洁,就是初始化TopMemoryContextErrorContext,完事。为了省地,把注释删了。在AllocSetContextCreate()中对TopMemoryContextErrorContext处理基本上是一样的。在MemoryContextCreate()中则有些不同,判断TopMemoryContext非空后就去调用另一个函数MemoryContextAlloc(),这个函数没干什么事,直接调用上面提到的虚拟方法表中的Alloc函数,它的具体实现是AllocSetAlloc()函数,在其中分配好空间,初始化和设置AllocBlockAllocChunk的属性,然后返回。接着在MemorycontextCreate()处理MemoryContextData结构的属性,其中把ErrorContextparent指向TopMemoryContext,处理完MemoryContextData的属性后返回返回到AllocSetContextCreate(),设置AllocSetContext的属性,这样就完成了ErrorContext的初始化。

       AllocSetAlloc()这个函数是pg中实际处理AllocSetMemoryContext涉及的内存空间分配的函数,这个分配机制比较复杂,还涉及到了另外两个结构AllocBlockAllocChunk,写pg的内存空间分配机制时再写吧。

       下面上初始化完以后的内存结构图

 

 




 

TopMemoryContextErrorContext的内存结构图一

 

 

上图中紫色的那一块是AllocBlock,中间浅紫色的那一小块是AllocChunk

       只有两个MemoryContext图就看着有点眼花缭乱了,看来以后得画抽象图了。

pg的内存管理主要是棵树,TopMemoryContext是树根,后面再建的MemoryContext就在根的下面。pg的内存管理实际是一个图,其主要部分是树形结构,另外子节点的partent指向了TopMemoryContext,形成了环。这样整个构成了图。这样的结构便于数据库的内存管理。

AllocSetContextblocks记录了分配给该Context的内存空间块AllockBlock的单向链表,freelist是空闲AllocChunk的链表数组。pg中给context分配内存时先分配AllockBlock,在AllockBlock里再分配AllocChunk,就是说AllocChunk是比AllockBlock小一级的内存空间单位。

上图中的ErrorContext所占的内存空间实际上在浅紫色的AllocChunk里,不是在外边,到写内存分配的时候再深入。上图是为了看清楚AllocBlockAllocChunk,没有把ErrorContext放到AllocChunk里,实际见下面这个图。

 

 



 

该图引用至http://blog.sciencenet.cn/home.php?mod=space&uid=419883&do=blog&id=308964

 

结束

 

 

 

 

  • 大小: 13.1 KB
  • 大小: 28.5 KB
  • 大小: 31.3 KB
  • 大小: 366.7 KB
  • 大小: 43.9 KB
  • 大小: 93 KB
0
0
分享到:
评论

相关推荐

    springmybatis

    MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan Old Java Objects,普通的Java对象)映射成数据库中的记录. orm工具的基本思想 无论是用过的hibernate,mybatis,你都可以法相他们有一个...

    R7.FeedbackButton:DNN 平台的反馈皮肤对象扩展

    自定义按钮外观、链接目标、文本和工具提示本地化。 请注意, DNN 反馈模块将包含所有查询字符串参数的整个 URL 存储在 UserAgent 字段中,该字段可通过将 [Feedback:UserAgent] 标签添加到项目模板来从反馈评论...

    前端-后端java的Util类的工具类

    卷 文档 的文件夹 PATH 列表 卷序列号为 000C-BB91 E:. │ config.properties │ Dao.java │ GeneratorDemo.java │ hibernate.cfg.xml │ HibernateDaoImpl.java │ HibernateSessionFactory.java ...

    ####这是一篇对python的详细解析

    python

    菜日常菜日常菜日常菜日常

    菜日常菜日常菜日常菜日常

    VB学生档案管理系统设计(源代码+论文).rar

    计算机专业毕业设计VB精品论文资源

    电商到底怎么做?淘系电商三维经营心法(59节课)-课程网盘链接提取码下载 .txt

    课程内容: 10-经营常见4大循环-被资本绑架思维.mp4 11-落地中的47个坑-产品坑.mp4 12-落地中的47个坑-一把手坑.mp4 13-落地中的47个坑-迷信坑.mp4 14-落地中的47个坑-缺乏坑.mp4 15-落地中的47个坑-团队坑.mp4 16-电商经营常见导致的10种挂法.mp4 18-淘系电商干法介绍.mp4 19-淘系电商的特点.mp4 20-淘系买家购物场景.mp4 21-淘系干法-标品.mp4 22-淘系电商干法-半标品.mp4 23-答疑.mp4 25-3类7种常见“干法”模型.mp4 26-6类产品日常运营报表.mp4 27-6类产品日常运营报表-高客单价店铺.mp4 28-6类产品运营报表-低客单价.mp4 29-6类产品运营报表-爆款数据模型季节性商品.mp4 2-前言.mp4 30-6类产品日常运营-标品.mp4 31-6类产品日常运营报表-非标品.mp4 32-6类产品日常运营报表-全店客服.mp4 33-执行就是一条:运营公式.mp4 35-搜索算法逻辑.mp4 36-2024年词层分层“激

    grpcio-1.63.0-cp312-cp312-linux_armv7l.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    labview使用DAQ采集数据时显示设备标识符无效

    当安装好NI-DAQmx后仍然无法运行采集程序,并且显示显示设备标识符无效,则需要添加虚拟采集设备。

    WX小程序源码无后台gank

    WX小程序源码无后台gank提取方式是百度网盘分享地址

    debugpy-1.6.4-py2.py3-none-any.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    VB中大迅通合同统计系统(论文+源代码).rar

    计算机专业毕业设计VB精品论文资源

    大学生毕业答辨ppt免费模板【不要积分】下载可编辑可用(144).zip

    大学生毕业答辨ppt免费模板【不要积分】下载可编辑可用(144).zip

    grpcio-1.46.5-cp36-cp36m-musllinux_1_1_i686.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    debugpy-1.0.0b2-cp35-cp35m-manylinux1_x86_64.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    grpcio-1.45.0-cp310-cp310-musllinux_1_1_i686.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    基于C++及Qt5开发的图片自动矢量化软件+高分辨率图像去噪+自动矢量化为svg/shp矢量图+不限定颜色种类和数量(高分项目)

    基于C++及Qt5开发的图片自动矢量化软件+高分辨率图像去噪+自动矢量化为svg/shp矢量图+不限定颜色种类和数量,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用~ 基于C++及Qt5开发的图片自动矢量化软件+高分辨率图像去噪+自动矢量化为svg/shp矢量图+不限定颜色种类和数量,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用~ 基于C++及Qt5开发的图片自动矢量化软件+高分辨率图像去噪+自动矢量化为svg/shp矢量图+不限定颜色种类和数量,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用~ 项目简介: 基于Qt5开发的图片自动矢量化软件,可对高分辨率图像进行去噪、自动矢量化为svg/shp矢量图,不限定颜色种类和数量,且不会产生缝隙,比adobe illustrator更好用

    debugpy-1.6.6-cp37-cp37m-win32.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    debugpy-1.6.5-cp39-cp39-win_amd64.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

    grpcio-1.48.2-cp310-cp310-musllinux_1_1_x86_64.whl

    Python库是一组预先编写的代码模块,旨在帮助开发者实现特定的编程任务,无需从零开始编写代码。这些库可以包括各种功能,如数学运算、文件操作、数据分析和网络编程等。Python社区提供了大量的第三方库,如NumPy、Pandas和Requests,极大地丰富了Python的应用领域,从数据科学到Web开发。Python库的丰富性是Python成为最受欢迎的编程语言之一的关键原因之一。这些库不仅为初学者提供了快速入门的途径,而且为经验丰富的开发者提供了强大的工具,以高效率、高质量地完成复杂任务。例如,Matplotlib和Seaborn库在数据可视化领域内非常受欢迎,它们提供了广泛的工具和技术,可以创建高度定制化的图表和图形,帮助数据科学家和分析师在数据探索和结果展示中更有效地传达信息。

Global site tag (gtag.js) - Google Analytics