DM数据库内存管理--内存检查

内存泄漏(Memory Leak)是指程序中已动态分配的内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

达梦数据库中提供MEMORY_LEAK_CHECK参数进行内存泄漏检查,如果打开MEMORY_LEAK_CHECL开关,系统会在V$MEM_REGINFO系统视图中登记每一次从內存池中分配内存的记录。

由于內存池使用伙伴系统算法管理,所以每块内存块都为2^x字节大小,对应RESERVD_SIZE列,而具体数据占用的内存通常不为2^x字节大小,对应DATA_SIZE列。

REFNUM列的数字代表了当前这行申请内存的代码被调用且没有释放的次数。REFNUM在申请内存时加1,在对应内存块释放时减1。

打开MEMORY_LEAK_CHECK开关,会对性能产生极大影响,建议只有在怀疑存在内存泄露时才开启,排查完毕立刻关闭开关。

下面通过实践来说明如何确认是否存在内存泄露:

1、机器配置清单:

序号

内存

Cpu

1

7.6G

4核

2、tpcc装载50个wearhouse,20并发

warehouses=50

loadWorkers=10

terminals=20

runMins=5

1、数据库主要参数设置

MEMORY_POOL = 1000

MEMORY_N_POOLS = 4

MEMORY_TARGET = 1000

BUFFER         = 2000

2、初始数据库buffer和mpool的大小

BUFFER_SIZE(M)

MEM_POOL(M)

TOTAL_SIZE(M)

2108

1143

3251

可以看出数据库启动时的内存大小和设置的buffer+MEMORY_POOL差不多。

3、启动tpcc测试

监控内存池的使用情况:

select name,org_size/1024/1024,total_size/1024/1024, target_size/1024/1024

from  v$mem_pool  where  n_extend_exclusive >0

NAME

ORG_SIZE(M)

TOTAL_SIZE(M)

TARGET_SIZE(M)

SHARE POOL 000

250

1191

250

SHARE POOL 001

250

1217

250

SHARE POOL 002

250

1267

250

SHARE POOL 003

250

1223

250

MON ITEM ARR

9

155

130

DICT CACHE

10

22

20

SQL CACHE MANAGERMENT

5

4223

15

 

从上面可以分析出:共享池有4个,每一个原始大小为250M,目标大小为250M,每个池池外扩展了将近1G,扩展的内存都是来源于操作系统。主要是dict和sql cache managerment进行扩展,导致共享池扩展。SQL CACHE MANAGERMENT扩展了4.2G和共享池的扩展差不多。

此时我们通过V$MEM_REGINFO视图,查看操作系统分配情况:

select sum(REFNUM),sum(RESERVED_SIZE)/1024/1024  from V$MEM_REGINFO  where  POOL  like  'NULL%';

SUM(REFNUM)

SUM(RESERVED_SIZE)/1024/1024(M)

17866

4185

可以看出pool=NULL,是从操作系统分配,分配了17866次,内存大小为4.185G,和上面分析的差不多。当程序执行完,再次查询确认已经释放:

SUM(REFNUM)

SUM(RESERVED_SIZE)/1024/1024(M)

6856

231

可以清晰的看到达梦数据库在运行过程中分配的内存,已经释放给操作系统。查看buffer和mpool的各自使用总量几乎为初始值

BUFFER_SIZE(M)

MEM_POOL(M)

TOTAL_SIZE(M)

2108

1259

3367

注意:如果REFNUM值很大,当程序运行结束也没下降,意味这当前由这行代码申请的内存一直没有被释放。此时需要提高警惕,排查系统是否出现内存泄漏。

3.2内存占用过高(oom)

上述的程序在服务器不重启的情况下,再次运行tpcc测试,此时数据库因为内存分配不足,导致系统处于等待状态,最终导致被操作系统oom。资源使用情况如下图所示:

达梦数据库使用的内存:

从top看达梦数据库的进程中virt和res中的内存要比实际使用的要高,怀疑是glibc库的malloc/free有自己的内存管理机制,并不会将这部分内存马上归还给OS。为了验证这个问题,又做了一个实验。

从上面我们看出SQL CACHE MANAGERMENT的扩展有4.2G都是来源于共享池。而共享池的扩展又来源于操作系统,这样就导致该进程的VIRT和RES比较高。即使程序free了分配的内存,glibc也没有及时将这部分内存归还给操作系统,导致下次在跑tpcc的时候又在分配内存,导致内存的增长,最终被操作系统oom。因此根据这个思路既然是SQL CACHE MANAGERMENT的计划池发生了扩展,那么将CACHE_POOL_SIZE设置大一点,尽量该内存池自持。因此将CACHE_POOL_SIZE设置1000,多次运行tpcc测试,内存的占用保持不变,未发生oom。监控内存使用情况如下:

几乎和我们通过视图查询出来的差不多。

下面对比下从v$sysstat查看出来的内存池的使用情况:

Name

STAT_VAL/1024./1024.(M)

memory pool size in bytes

2433(内存池总的大小)

memory used bytes

1731(内存池使用的内存大小)

memory used bytes from os

385(内存池从操作系统分配的大小)

从这里看出内存池使用了1731M+buffer(2g),和top中看到的res值差不多。

总结:尽量保持每个内存池自持,减少从池外分配。 

3.3 关注备份池的使用

1、操作系统物理内存:7812M

2、数据库的主要参数设置:

MEMORY_POOL    = 500

MEMORY_TARGET   = 0

BUFFER           = 1000

RECYCLE           = 100

SORT_BUF_SIZE     = 2048

DICT_BUF_SIZE     = 1000

SESS_POOL_SIZE    = 1024

VM_POOL_SIZE     = 64

3、数据库的前台命令行打印:

out of memory, fail to allocate memory from OS

out of memory, fail to allocate memory from OS

out of memory, fail to allocate memory from OS

out of memory, fail to allocate memory from mem pool: BACKUP POOL

out of memory, fail to allocate memory from OS

out of memory, fail to allocate memory from mem pool: BACKUP POOL

out of memory, fail to allocate memory from OS

out of memory, fail to allocate memory from OS

out of memory, fail to allocate memory from OS

out of memory, fail to allocate memory from mem pool: BACKUP POOL

out of memory, fail to allocate memory from OS

out of memory, fail to allocate memory from mem pool: BACKUP POOL

Killed

当从操作系统分配失败,转而向备份池申请,最终导致被操作系统oom了。当看到从备份池分配时,需要重点关注。存在很大的可能会被操作系统kill。内存池在申请内存时的原则是:超过扩展的大小的内存先从共享池,共享池不够,共享池在从操作系统分配。操作系统也分配失败时,才从备份池申请。因此当发现从备份池申请时需要高度重视。

3.4 内存增长过快分析

1、问题描述:外面项目反馈,分区表中对大字段列进行max(length(file_id))会导致CPU暴增。

2、重现的SQL:

--1、创建表

CREATE TABLE USER_MAIL_INDEX_0

(

ACCT_ID BIGINT DEFAULT '0' NOT NULL,

file_id  text,

MAIL_ID BIGINT DEFAULT '0' NOT NULL,

THREAD_ID BIGINT DEFAULT '0' NOT NULL,

CONSTRAINT PK_MAIL_INDEX_0 NOT CLUSTER PRIMARY KEY(ACCT_ID, MAIL_ID))

PARTITION BY HASH(ACCT_ID)

 PARTITIONS 100 STORAGE(USING LONG ROW, ON MAIN, CLUSTERBTR) ;

------2、插入数据

begin

 for i in 1..1000000 loop

    insert into USER_MAIL_INDEX_0 values(i,'dadfdsgfdgfdd',i-1,9);

 end loop;

end;

commit;

-------3、执行查询

select max(length(file_id)) from user_mail_index_0;

3、参数设置:

MEMORY_POOL   = 100

MEMORY_TARGET  = 500

BUFFER           = 1000

RECYCLE           = 64

4、现象:内存增长的特别快,在一些内存配置比较小的机器上(8G),会被操作系统OOM

数据库刚启动后的内存情况:

执行查询sql:30秒的内存情况,8G的内存都被吃完:

5、分析

1、通过查询监控内存的使用,确认是哪块内存在增长

select

(select sum(n_pages * page_size)/1024/1024 from v$bufferpool)||'MB' as BUFFER_SIZE,

( select sum(total_size)/1024/1024 from v$mem_pool)||'MB' as mem_pool,

(select sum(n_pages * page_size)/1024/1024 from v$bufferpool)+(select sum(total_size)/1024/1024 from v$mem_pool)||'MB' as TOTAL_SIZE

From  dual;

在启动前查询下上述语句,记录初始值。然后在内存增长的时候,在查询该语句。发现是v$mem_pool在增长。那么我们怎么知道是哪个内存池在内存一直在堆积不释放呢?

2、打开MEMORY_LEAK_CHECK

alter system set 'MEMORY_LEAK_CHECK'=1 ;

select  * from  v$dm_ini where  para_name like  '%MEMORY_LEAK_CHECK%;

3、查询 V$MEM_REGINFO视图,关注REFNUM字段,如果这个字段很大,就说明存在内存堆积的情况,需要将对应的结果反馈给研发,以帮助研发进一步分析。

select  * from V$MEM_REGINFO  ORDER BY  REFNUM  DESC;

--结果如下图所示:

从该图上可以看到是VM的内存池在增长,根据前面第一章的基本原理,我们已知VM上的内存是从session池来的,SESSION池如果不够,扩展的内存是从共享池(SHARE_POOL),而如果share_pool的内存不够,是从操作系统分配的。既然找到是VM池的增长导致的,那么我们就需要把上图的VIRTUAL MACHINE池的LINENO、refnum、fname提供给研发。PS:另外设置MEMORY_TARGET,可以在内存比较大的时候,从os里面分配出来的内存可以在sql运行完以后在收缩到MEMORY_TARGET设置的大小。

达梦数据库 - 新一代大型通用关系型数据库 | 达梦在线服务平台达梦数据库产品体验站,DM8在线试玩,达梦数据库全系列产品免费下载,官方权威的快速上手文档和产品手册,最活跃的达梦技术社区,面向全行业ISV厂商免费的云适配服务。icon-default.png?t=M7J4https://eco.dameng.com

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值