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

来源:这里教程网 时间:2026-03-03 20:21:06 作者:

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://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 + 64M*127 = 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可看堆栈默认值,也可配置堆栈默认值。

  • 相关推荐