greenplum中的内存分配方法

在这里插入图片描述
context 与 account 是 多对多关系,context 与模块有关(MessageContext,ErrorContext,PortalMemory等),account 与任务实体有关(MEMORY_OWNER_TYPE_MemAccount, MEMORY_OWNER_TYPE_Planner,MEMORY_OWNER_TYPE_Exec_Sort等)。
每执行完一个query会清理一些类似的memorycontext,重置所有account(MemoryAccounting_Reset)并把剩下的account计入rollover memory account中,但剩余的 context 不会被重置。

比如缓存的context(CacheMemoryContext),它还在原来的 context 中,而对应 account 剩下的内存会给到 rollover 去。

gp中先分配虚拟内存,再分配物理内存。回收时也是先回收虚拟内存,再回收物理内存(可能是放回freelist,可能是真的free)
对于同一个account 和 MemoryContext,chunk中的standardHeader中有指向同一个shareHeader的指针。
物理空间的申请以block为单位,一个block可以分为多个chunk,这些chunk按空间大小放在alloclist或freelist的相应大小的链表中。
以下是所有alloc相关方法
在这里插入图片描述
在这里插入图片描述

那么内存是如何与内存帐户绑定在一起的呢?

这里先假定我们分配的是一个很大的内存,比freelist能容纳的最大内存chunk还要大,这时会分配的block中将只有一个chunk,我们来描述下这个过程:
一般创建帐户是用MemoryAccounting_CreateAccount,会在MemoryAccountMemoryContext下创建一个MemoryAccount结构体。
当用 MemoryAccounting_SwitchAccount 切换时,会将 ActiveMemoryAccountId 切换到这个帐户下。

在我们调用palloc之类的函数分配内存时,会调用AllocSetAlloc方法(上图中的第一个函数),内部用gp_malloc先调用VmemTracker_ReserveVmem留出一块虚拟内存,再用标准c的malloc分配一块内存,最后把这块内存头加上VmemHeader(虚拟内存标识),这样就得到了一个block(即vmemHeader后面的部分),去掉block的头(AllocBlock)即是各实际的chunk(这里描述场景只有一个chunk,如果分配内存没有很大,将会把block切分为多个size的chunk,放在freelist中,取最合适的一块chunk返回),每个chunk的头部(AllocChunk)有一个SharedChunkHeader,相同帐户的这个header是一样的。

那么帐户与context又是怎么绑定的呢?

还是在AllocSetAlloc函数中,gp_malloc已经让我们得到一块block,我们先假设这个block只有一个chunk,接下来会把这个block放在set->blocks上(这里的set是MemoryContext的超集,其第一个元素即是传入的MemoryContext),接下来会用MemoryContextNoteAlloc去计算和更新当前虚拟内存大小,然后调用AllocAllocInfo做真正的chunk(实际用的内存)与帐户的绑定。

chunk与帐户之间关系的绑定有三步:

首先找当前帐户的共享header,即ActiveMemoryAccountId(一个帐户只有一个共享header,一个context可以有多个帐户和一个匿名null帐户)对应的header,在chunk上绑定这个header
在这里插入图片描述

然后调用MemoryAccounting_Allocate在这个帐户加上新分配的chunk的大小(包含chunk的头的大小) ,

最后把这个chunk放在当前context上
在这里插入图片描述
AllocSetAlloc最终返回的是chunk去掉header后的内存:
在这里插入图片描述
即我们真正用的内存

释放内存

释放内存的函数是MemoryContextDelete->(*context->methods.delete_context) (context)即 AllocSetDelete 方法,首先会调用MemoryContextDeleteAllocSetReleaseAccountingForAllAllocatedChunks,在context的各shareheader帐户上减去其内存,在总的MEMORY_OWNER_TYPE_SharedChunkHeader上也减去相应内存。将memoryContext的alloclist和sharedHeaderList置空

然后取出所有的block( set->blocks ),对每个block调用MemoryContextNoteFree从这个context的每个父context上减去这一block的内存,再调用gp_free(先释放(free)物理内存,再在虚拟内存上减去相应内存大小)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值