在DB2的体系结构中,并非所有代码都在数据库引擎的核心进程里执行。存储过程、用户自定义函数(UDF)以及防护式存储器集这类对象,默认运行在独立的fenced进程中,也就是我们常在进程列表里看到的db2fmp。这种设计的目的很明确:一旦第三方代码出现非法内存访问或崩溃,受影响的只是那个独立的fenced进程,数据库引擎本身不会被动摇。而控制这些fenced进程在任务执行完之后去留的开关,就是数据库配置参数keepfenced。理解这个参数的工作机制,对排查内存占用问题和优化存储过程调用性能都很有帮助。

fenced模式的隔离原理与db2fmp进程
DB2把代码执行环境分成了两大类:trusted(受信任)和untrusted(不受信任,即fenced)。运行在受信任模式下的例程直接在数据库代理进程中执行,速度快、开销小,但前提是代码质量必须可靠,因为任何内存越界都可能直接损坏引擎地址空间。而fenced模式则把例程放到独立的操作系统进程中运行,DB2通过共享内存段和IPC机制与这些db2fmp进程通信。
这种隔离带来的最大好处是故障隔离。想象一个用C语言编写的UDF,如果里面存在野指针,在受信任模式下数据库代理进程会直接崩溃,严重时导致整个实例异常;而在fenced模式下,崩溃的只是那个db2fmp进程,DB2能捕获到这个失败并把错误干净地返回给应用程序,数据库整体继续正常运转。对于来源不可控的第三方代码、Java存储过程等,fenced是更稳妥的选择。
db2fmp进程按处理模式可以分为两种类型:MULTI-ALT(多线程通用型)和SINGLE-ALT(单线程独占型)。大多数线程安全的例程会共享一个多线程db2fmp进程,而非线程安全或需要特定环境的例程则会拿到专属的单线程进程。keepfenced参数正是作用在这些进程的回收策略上,决定了它们是常驻待命还是用完即走。
keepfenced参数取值的行为差异
keepfenced是一个布尔类型的数据库配置参数,取值YES或NO。当设置为YES(默认值)时,db2fmp进程在执行完例程后不会退出,而是保留在内存中等待下一次调用。这样一来,后续再次调用同一个存储过程或UDF时,DB2直接复用现成的进程,省去了fork进程、加载代码、初始化运行时环境(尤其是Java虚拟机的启动)这一整套昂贵操作。对于频繁调用Java存储过程的系统,这个差异可能体现在数百毫秒级别的响应时间上。
当设置为NO时,db2fmp进程在完成当前任务后立即被销毁。这种配置的内存占用最干净,每次调用结束,进程占用的私有内存全部归还操作系统。代价是每次调用都要重新创建进程,冷启动延迟明显增加,对高频小请求场景的吞吐量影响较大。
两种取值各有适用面。如果你的fenced例程存在缓慢的内存泄漏,keepfenced为YES会让泄漏随着进程存活不断累积,最终触发内存告警;此时设为NO相当于每次调用后自动回收,反而成了一种简易的泄漏规避手段。反之,如果例程本身质量可靠且调用频繁,保留进程显然是更优解。可以通过下面的命令查看当前设置:
-- 查看数据库配置中的keepfenced设置 db2 get db cfg for SAMPLE | grep -i keepfenced -- 输出示例: -- Keep fenced process (KEEPFENCED) = YES -- Max kept fenced processes (FENCED_POOL) = MAX_COORDAGENTS
注意输出中还有一个配套参数fenced_pool,它限制了最多可以保留多少个db2fmp进程。如果keepfenced为YES但fenced_pool设得过小,进程复用的效果也会打折扣。此外修改keepfenced是动态生效的,不需要重启实例:
-- 修改keepfenced为NO,用完即销毁fenced进程 db2 update db cfg for SAMPLE using KEEPFENCED NO -- 同时调整保留进程池上限 db2 update db cfg for SAMPLE using FENCED_POOL 20
实际场景中的选择建议与排查思路
在决定keepfenced取值之前,先弄清楚系统里有没有fenced例程、调用频率如何。可以通过系统编目视图快速确认,例如查询SYSCAT.ROUTINES中ROUTINETYPE相关字段,检查存储过程是用SQL写的(内联执行,不涉及db2fmp)还是外部语言实现的(走fenced路径)。纯SQL PL存储过程不受这个参数影响,只有EXTERNAL例程才真正依赖db2fmp进程。
对于常见的三类场景,可以这样取舍。第一类是高频率调用Java存储过程的OLTP系统,建议保持YES并适当调大fenced_pool,让JVM常驻内存,避免每次调用都付出JVM初始化的代价。第二类是每天只跑几次的批处理作业,例程调用间隔很长,保留进程纯属浪费内存,设为NO更合适。第三类是怀疑例程存在内存泄漏的过渡期,把keepfenced改为NO可以让每次调用后内存彻底释放,为修复代码争取时间。
排查db2fmp相关问题时,可以结合操作系统工具观察进程行为。在Linux上用ps配合grep查看db2fmp进程数量和RSS内存:
# 统计实例下的db2fmp进程数量 ps -ef | grep db2fmp | grep -v grep | wc -l # 查看每个db2fmp进程的内存占用(KB) ps -eo pid,rss,cmd | grep db2fmp | grep -v grep
如果发现db2fmp进程的RSS持续增长且从不回落,基本可以判断是例程内部泄漏,配合keepfenced NO或定期重启数据库可以缓解症状,但根治还得修改例程代码。另外要注意,keepfenced为YES时保留的进程会一直占用实例的内存配额,在内存紧张的分区数据库或纯内存实例环境中,这部分开销需要纳入容量规划。
总的来说,keepfenced是一个小而关键的参数:它不改变隔离的本质,只调节隔离的代价。隔离靠的是fenced进程机制本身,keepflected决定的是这份隔离是一次性投入还是按次付费。结合例程的语言类型、调用频率和内存预算来设置它,才能让安全性与性能各得其所。
DB2keepfencedfenced用户进程数据库配置参数修改时间:2026-09-07 09:24:43