17.3. 存储器管理

Table of Contents
SPI_copytuple — 在上层执行器环境制作元组的拷贝
SPI_copytupledesc — 在上层执行器环境中制作一份元组描述符拷贝
SPI_copytupleintoslot — 在上层执行器环境中制作元组及描述符的拷贝.
SPI_modifytuple — 通过替换一个给出元组的选定字段创建一个元组
SPI_palloc — 在上层执行器环境中分配存储器
SPI_repalloc — 重新在执行器上层环境中分配存储器
SPI_pfree — 在上层执行器环境中释放存储器
SPI_freetuple — 释放一个在上层执行器环境里分配的元组
SPI_freetuptable — 释放一个 SPI_exec 或类似的函数 创建的元组集
SPI_freeplan — 释放一个前面保存的规划

PostgreSQL 在存储器环境 中分配存储器,它提供了在许多地方分配有着不同的生命期的许多内存块的 一个方便的管理方法.删除一个环境则释放所有在其内部分配的内存. 因此,我们没必要跟踪独立的对象以避免内存泄漏 --- 只有少量的 环境需要管理.palloc 和相关的函数从 "当前"的环境中分配内存.

SPI_connect 创建一个新的存储器环境 并且将其标记为当前的环境.SPI_finish 恢复前一个内存环境并且删除 SPI_connect 创建的环境.这些动作确保在你的过程中分配的临时内存在 过程结尾的时候都被回收,避免内存泄漏.

不过,如果你的过程需要返回一个已分配的内存对象 (比如一个传递引用的数据类型),那么你就不能用 palloc 分配返回的对象, 至少是不能在你已经和 SPI 联接上的时候.如果你试图这么做, 那么该对象将在 SPI_finish 的时候被释放, 因而你的过程就不能可靠地工作了!

要解决这个问题,使用 SPI_palloc 分配你的 返回对象.SPI_palloc"上层执行器" 内存中分配空间 --- 也就是调用 SPI_connect 的生成当前环境的时候的内存环境,该环境是从你的过程返回数值的 正确环境.

如果还没有联接到 SPI 的时候调用它,SPI_palloc 的行为和简单的 palloc 一样.

在一个过程和 SPI 管理器联接之前,当前的内存环境 是上层执行器环境,因此所有该过程使用 palloc 或者 SPI 工具函数分配的空间都是在这个环境中分配的.

在调用 SPI_connect 之后,当前环境是 该过程私有的,由 SPI_connect 制作的环境. 所有通过 palloc/repalloc 或者 SPI 工具函数(除了 SPI_copytupleSPI_copytupledescSPI_copytupleintoslotSPI_modifytuple, 和 SPI_palloc) 分配的内存都是在这个 环境中分配的.

如果一个过程与 SPI 管理器断开(通过 SPI_finish),那么当前 环境恢复为上层执行器环境,并且所有在该过程的内存环境 中分配的内存都释放掉并且不能再次使用!

所有在本节内描述的函数都可以在已联接的和未联接的 过程中使用.在未联接的过程中,他们的行为和下层的 原始后端函数(palloc 等)相同.