PG源码分析系列:内存上下文PG电子-电子平台-官方网站
Pocket Games Soft 是世界一流的手机游戏开发商。[永久网址:wdhash.com]致力于在iOS,Android和HTML5平台上提供前所未有,身临其境的移动游戏解决方案,为提供玩家安全优质的pg电子,PG游戏试玩,PG电子官方网站,pg电子游戏,pg游戏,pg电子app,PG APP下载,pg电子平台,PG模拟器,pg娱乐,欢迎注册体验!title: Pgsql源码分析——内存上下文 date: 2018-05-01 22:00:00 categories: - Postgresql - PgSource Postgresql内存上下文源码分析 1 数据库内存上下文 postgresql在7.1版本引入了内存上下文机制来解决日益严重的内存泄漏的问题,在引入了这种“
title: Pgsql源码分析——内存上下文 date: 2018-05-01 22:00:00 categories: - Postgresql - PgSource
postgresql在7.1版本引入了内存上下文机制来解决日益严重的内存泄漏的问题,在引入了这种“内存池”机制后,数据库中的内存分配改为在“内存上下文中”进行,对用户来说,对内存的申请由原来的malloc、free变成了palloc、pfree。对内存上下文的常用操作包括:
内存片(CHUNK):用户在内存上下文中申请(palloc)到的内存单位。内存块(BLOCK):内存上下文在内存中申请(malloc)到的内存单位。
AllocSetContext是内存上下文的核心的控制结构,我们在代码中经常看到的内存上下文TopMemoryContext的定义为:
那么MemoryContextData和AllocSetContext是什么样的关系呢?请看下图左半部分。
由于AllocSetContext结构中的首部存放着MemoryContextData指针,所以这种转换可以成功。这样的使用方法有些类似与类的继承:MemoryContextData代表父类,AllocSetContext在父类(头部的指针)的基础上增加了一些新的功能。实际上PG就是使用了这种机制实现了interface(MemoryContextData作为interface),而后面的实现可以有很多种(AllocSetContext是内存上下文的一种实现)。好说到这里言归正传,继续介绍MemoryContextData数据结构的功能:
methods:保存着内存上下文操作的函数指针(例如palloc、pfree)
MemoryContextData使内存上下文形成了一个二叉树的结构,这样的数据结构增加了内存上下文的易用性,即在重置或删除内存上下文时,所有当前上下文的子节点也会被递归的删除或重置,避免错删或漏删上下文。methods中保存的全部为函数指针,在内存上下文创建时,这些指针会被赋予具体函数地址。下面继续介绍AllocSetContext数据结构:
blocks:内存块链表,内存上下文向OS申请连续大块内存后,空间由blocks链表维护
内存片存在于内存块以内,是内存块分割后形成的一段空间,内存片空间的头部为AllocChunkData结构体,后面跟着该内存片的空间,实际上palloc返回的就这指向这段空间首地址的指针。内存片有两种状态:AllocSetContext中freelist数组中存放的是内存片指针是被回收的内存片;另外一种内存片是用户正在使用的内存片。(注意两种状态的内存片都存在于内存块中,被回收只是改变内存片aset指针,形成链表保存在freelist中;在使用中的内存片aset指针指向所属的AllocSetContext)
allocset会在自己维护的内存块链表(blocks)中寻找空间构造内存片,然后分配给用户。
申请新的内存块追加到blocks链表中,在其中分配新的内存片分配给用户。
内存片的数据结构相对简单,空指针aset是一个复用的指针,当内存片正在使用时,aset指向它属于的allocset结构,当内存片被释放后,内存片被freelist数组回收,aset作为实现链表的指针,用于形成内存片的链式结构。
内存块是内存上下文向操作系统申请的连续的一块内存空间,申请后将AllocBlockData结构置于空间的首部,其中freeptr和endptr用与指向当前内存块中空闲空间的首地址和当前内存块的尾地址,见图2-1中的“连续内存段(内存块)”。aset指向控制结构AllocSetContext,next指针形成内存块的链式结构。
这是一个存放内存片指针的数组,数组中每一个元素都是一个内存片指针,就像前面提到的,空闲内存片会形成链表结构,而链表的头结点的指针就存放在这个数组中。从长度来看,这个数组可以保存11个内存片的链表,每一个链表都保存这特定大小的内存片:
图2-2描述的就是freelist数组的结构,数组下标0位置保存8字节的内存片,下标1位置保存16字节的内存片,以此类推,freelist中可以保存的最大的内存片为8k字节。相同大小的内存片会串在同一个链表中,放在freelist中指定的位置,数组下标的计算按照公式:log(Size)-3。例如大小为512字节的内存片被释放了,套用公式log(512)-3=5,那么这个内存片就会维护到freelist[5]指向的链表中。(具体计算过程见AllocSetFreeIndex函数)。
让我们看几个数据库中最常见的上下文创建时的参数,结合具体值在说说创建时参数的作用:
minContextSize:如果这个值设定了并超过了一定大小(一个内存块结构体加上一个内存片结构体的大小),那么在创建上下文时立即申请一个内存块,大小为minContextSize。上图中我们可以看到大部分上下文minContextSize都为0,那么ErrorContext的minContextSize为8k有什么作用呢?在系统出现OOM时,内存空间已经耗尽,但是ereport的错误处理流程仍然需要申请内存空间去打印错误信息,但系统已经没有内存可以申请了。这时ErrorContext中保留的8k空间可以保证最后的错误处理流程可以正确执行。
allocChunkLimit:这里引出一个重要的参数,内存片申请阈值,这个值被开始被设为8k字节,但是后面会适当缩小到maxBlockSize的1/8。这个参数的调整是为了减少内存片空间的浪费(内存块中的最后一段内存不足以放下一个内存片,所以这段空间被舍弃掉了,理论上浪费掉的空间最大为allocChunkLimit)
回收当前内存块的剩余空间:将剩余空间切割成freelist能保存的最大值,例如1000字节的内存片回收时首先申请512字节的内存片,然后挂在freelist[6]上,剩余488字节申请256字节的内存片挂在freelist[5]上,剩余232字节继续上面处理流程,直到最后空间小于8字节为止。
在多次申请内存块后,内存块的大小总会等于maxBlockSize,这样如果出现内存泄漏导致OOM时,如果某一个内存上下文非常大,可以利用这个特点分析内存问题的根因。例如每100次申请8M的内存块时,打印一次Backtrace。
这个函数会被MemoryContextStats递归调用,遍历内存上下文树的内个节点,并获取当前节点的信息。
GDB调试时这一个非常好用的函数,可以直接在log中打印内存上下文树,指令:
Java Review - 线程池中使用ThreadLocal不当导致的内存泄漏案例&源码分析
Java Review - 线程池中使用ThreadLocal不当导致的内存泄漏案例&源码分析
全网最硬核 Java 新内存模型解析与实验 - 5. JVM 底层内存屏障源码分析
全网最硬核 Java 新内存模型解析与实验 - 5. JVM 底层内存屏障源码分析
JVM源码分析之警惕存在内存泄漏风险的FinalReference(增强版)
JVM源码分析之警惕存在内存泄漏风险的FinalReference(增强版)
前段时间,在排查一个问题的时候,遇到了一个有点令人困惑的情况,有下面这两段代码:
本文详细介绍了Java虚拟机运行时数据区的各个方面,包括其定义、类型(如程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和直接内存)及其作用。文中还探讨了各版本内存区域的变化、直接内存的使用、从线程角度分析Java内存区域、堆与栈的区别、对象创建步骤、对象内存布局及访问定位,并通过实例说明了常见内存溢出问题的原因和表现形式。这些内容帮助开发者深入理解Java内存管理机制,优化应用程序性能并解决潜在的内存问题。
阿里云服务器实例规格怎么选?经济型、通用算力型、计算型、通用型、内存型场景化选购指南
NoProp:无需反向传播,基于去噪原理的非全局梯度传播神经网络训练,可大幅降低内存消耗
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
PyTorch CUDA内存管理优化:深度理解GPU资源分配与缓存机制
阿里云服务器ECS内存型2核16G、4核32G和8核64G配置实例、费用和性能参数表
阿里云服务器实例经济型e、通用算力型u1、计算型c8i、通用型g8i、内存型r8i详解与选择策略
JVM内存问题之如何比较不同时间点的pmap输出以检查新增或变大的内存段
JVM内存问题之top命令的物理内存信息中,used和free,avail Mem分别表示什么
JVM内存问题之在业务有损的情况下,遇到JAVA内存使用率高的问题,应该如何快速止损
Redis性能优化问题之当Redis内存达到maxmemory后,淘汰数据的逻辑是怎样的