YashanDB · 8月16日 · 广东

【YashanDB知识库】virt虚拟内存远大于res内存问题分析

YASDB内存占用简介

参数配置:

默认参数配置:DBMS_PARAM高级包生成配置参数

数据库内存配置,使用默认参数步骤:

1、DBMS_PARAM.OPTIMIZE(); //生成默认参数,使用总内存的80%

2、SELECT DBMS_PARAM.SHOW_RECOMMEND() FROM dual; //查看生成的参数

3、EXEC DBMS_PARAM.APPLY_RECOMMEND(); //应用参数,需要重启yasdb

文档路径:YashanDB Doc (yasdb.com)

内存占用计算参数:

DATA_BUFFER_SIZE VM_BUFFER_SIZE SHARE_POOL_SIZE LARGE_POOL_SIZE SCOL_DATA_BUFFER_SIZE COLUMNAR_VM_BUFFER_SIZE 主要是上面这些参数配置内存的总和 + 256M(其他小块内存)

问题:VIRT超过RES十几个G

如下图所示,yasdb满负荷运行后,0任务跑的情况下,virt内存:31.2g,实际内存:21.7g,虚拟内存比实际内存大了10g左右,虚拟内存远大于实际使用内存。

YASDB内存使用情况

yasdb参数配置,如下图:

按照yasdb主要内存占用计算:

DATA_BUFFER_SIZE(18306M) + VM_BUFFER_SIZE(2382M) + SHARE_POOL_SIZE(512M) + LARGE_POOL_SIZE(1G) + SCOL_DATA_BUFFER_SIZE(128M) + COLUMNAR_VM_BUFFER_SIZE (128M) = 22480M(21.95g)

RES 21.7g的内存使用和yasdb内存总占用数相符合。

VIRT内存为什么远远大于RES

VIRT:SWAP+RES(虚拟内存大小,包括进程使用的库、代码、数据等,如果申请100M,则增加100M大小)

RES:进程使用的,未被换出的物理内存(包括共享内存大小,如果申请100M,使用10M,则实际为10M)

mmap查看yasdb使用情况

如下图:

strace -f -e "brk,mmap,munmap" -p 2051595

yasdb没有使用mmap等映射接口。

pmap工具,查看进程内存映射信息

pmap命令用于报告进程的内存映射关系(查看进程的内存映像信息)

选项:

  • -x, --extended:显示扩展格式
  • -d, --device:显示设备格式
  • -X:显示比 -x 选项更多的详细信息。注意:格式根据 /proc/PID/smaps 更改
  • -p, --show-path:在映射列中显示文件的完整路径
  • -h, --help:显示帮助信息并退出
  • -V, --version:显示版本信息并退出

扩展格式和设备格式域:

  • Address: start address of map 映像起始地址
  • Kbytes: size of map in kilobytes 映像大小
  • RSS: resident set size in kilobytes 驻留集大小
  • Dirty: dirty pages (both shared and private) in kilobytes 脏页大小
  • Mode: permissions on map 映像权限: r=read, w=write, x=execute, s=shared, p=private (copy on write)
  • Mapping: file backing the map , or ‘[ anon ]’ for allocated memory, or ‘[ stack ]’ for the program stack. 映像支持文件,[anon]为已分配内存 [stack]为程序堆栈
  • Offset: offset into the file 文件偏移
  • Device: device name (major:minor) 设备名

pmap -d ${pid}

glibc分配内存机制

  • 导致这种问题的原因是使用glibc的Arena内存池分配了大量的虚拟内存。
  • glibc大于2.1.1版本时,在glibc分配内存的时候,大内存从从中央分配区分配,小内存则在线程创建时,从缓存区分配。
  • 为了解决分配内存的性能的问题,就引入了这个叫做arena的memory pool。而恰好,在64bit系统下面,它的缺省配置为64M。
  • 一个进程可以最多有cores 8个arena,假如服务器是4核的,那么最多有4 8=32个arena,也就是32 * 64 = 2048M内存

参考文档:

[
](https://www.cnblogs.com/sky-h...)

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/6.0_release_notes/compiler

glibc版本:

内核数 cores:

MALLOC_ARENA_MAX:

环境变量,控制arena内存池个数。

查看状态:

cat /proc/pid/status

测试arena内存池代码程序:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <pthread.h>
 
bool kill_th = false;
 
void *th_func(void *arg){

        int s = 0;
        //int size = 1024*1024*139;
        int size2 = 1024;
        //char *pbuf;
        while(!kill_th){
                if(s == 0){
                   //pbuf = (char *)malloc(size);
                  // free(pbuf);
 
                   char *pbuf2 = (char *)malloc(size2);
                   free(pbuf2);
                   s = 1;
                }
 
                sleep(1);
        }
        //free(pbuf);
}
 
void create_thread(){
    pthread_t tid;
    int nums = 256;
    for(int i = 0; i< nums;i++){
        pthread_create(&tid,NULL,th_func,NULL);
        pthread_detach(tid);
    }
         
    while(getchar()){
        kill_th = true;
        getchar();
        break;
    }
    return ;
}
 
int main(int argc,const char **argv) {
    create_thread();
    return 0;
}

超过64M大小的空间不从arena内存池申请。

编译:gcc test.c -lpthread

ulimit -a:

运行测试程序 : ./a.out:

默认MALLOC_ARENA_MAX

arena池默认个数:16 * 8 = 128

默认,cat /proc/$pid/environ,如下图:

该文件没有MALLOC_ARENA_MAX参数

● 256个线程

内存使用情况:

pmap -p pid 信息如下:pmap_malloc_arena_max_normal.txt

arena内存池:127 *(65344K + 192K)

线程栈空间:256 * 8192K

8192K 256 + 64M127 = 10176M,

再加上其它小空间,符合虚拟内存使用情况。

● 256个线程退出

内存使用情况:

pmap映射进程信息:pmap_maloc_arena_normal_thread_exit.txt

arena内存池:127 *(65344K + 192K)= 8128M

栈空间:仅剩主线程空间

可以看出,线程退出后,arena空间并没有释放。

export MALLOC_ARENA_MAX = 4

MALLOC_ARENA_MAX 值: cat /proc/$pid/environ:

可以看到参数MALLOC_ARENA_MAX 配置为4

● 256个线程

top信息:

pamp -p pid信息: pmap_malloc_arena_max=4.txt

线程栈空间:256*8M

arena内存池:3 * (65344K + 192k)

● 256线程退出

top信息:

pamp -p pid信息,如下图:

arena内存池:3 * (65344K + 192k)

yasdb的内存映射情况

参数

WORK_AREA_STACK_SIZE 2M

WORK_AREA_HEAP_SIZE 512K

得知栈空间大小为2M,堆空间为512K

分析pmap信息

pmap -p {pid}(yasdb),文件:pmap_yasdb.txt

arena内存池:97 (65024K+512k) + 5 (65216K+320k) + 1(64576K +960K ) + 1 (53824K + 11712K) + 23 (64896K + 640K) = 127 64M = 8128 M

栈空间:390 1984K + 9 8192K = 827.625M

其它:lib库映射空间等

总共相加,大概可以得出与多出的虚拟内存相等。

配置线程参数一些接口

每个线程都会分配一个栈(默认8M,可配置)和一个堆空间。

pthread_attr_t attr;

pthread_attr_init(&attr);

pthread_attr_setstacksize(&attr, stackSize); //配置线程属性->栈空间大小

prctl(PR_SET_NAME, name); //设置线程名

pthread_detach(tid); //线程退出后,自动释放空间。如果没有配置这个需要主动释放pthread_exit。不然会一直占用虚拟内存

ulimit -a可看堆栈默认值,也可配置堆栈默认值。

推荐阅读
关注数
1
文章数
35
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息