Linux内存(1):进程内存

目录

遇到的问题

我们有时会遇见下图这样的情况,用top命令看一个进程,发现VIRT内存使用的特别多,有时甚至会超过物理内存,这个篇文章就是来分析一下这钟现象.

linux_mem_1_1.png

图1  top命令结果

   我们可以看到3438这个进程,的VIRT内存达到了45G,这个是什么原因呢? VIRT的内存是虚拟内存的意思,什么是虚拟机内存呢,虚拟内存是进程认为自己可以用的
内存,这个的大小的最大值和操作系统有关系,64位的操作系统会有很大的空间.,每个进程可以看到的可使用的虚拟内存空间都是一样多的.所以进程在申请内存时,可以
申请到比物理内存还要多的虚拟内存.进程的虚拟内存如果被使用,这时会反映在RES段上,RES是一个进程实际使用的物理内存,我将用下面几个实验进一步的说明.

先看一下下面经典的进程的内存结构图

linux_mem_1_2.jpg

图2  内存结构

我们看一下top中那个进程的内存情况

test]# pmap -x `pgrep JTransponderd` 
Address           Kbytes     RSS   Dirty Mode   Mapping
0000000000400000    1316     904       0 r-x--  JTransponderd
0000000000749000       4       4       4 rw---  JTransponderd
000000000074a000       4       4       4 rw---    [ anon ]
000000000196c000  118368  103988  103520 rw---    [ anon ]
0000003798c00000     128     112       0 r-x--  ld-2.12.so
0000003798e1f000       4       4       4 r----  ld-2.12.so
0000003798e20000       4       4       4 rw---  ld-2.12.so
......
//动态申请了很多10240kb的内存,但是都没有完全使用
00007f67dc94c000       4       0       0 -----    [ anon ]
00007f67dc94d000   10240      68      68 rw---    [ anon ]
00007f67dd34d000       4       0       0 -----    [ anon ]
00007f67dd34e000   10240      20      20 rw---    [ anon ]
00007f67ddd4e000       4       0       0 -----    [ anon ]
00007f67ddd4f000   10240      68      68 rw---    [ anon ]
00007f67de74f000       4       0       0 -----    [ anon ]
00007f67de750000   10240      40      40 rw---    [ anon ]
00007f67df150000       4       0       0 -----    [ anon ]
00007f67df151000   10240      68      68 rw---    [ anon ]
00007f67dfb51000       4       0       0 -----    [ anon ]
00007f67dfb52000   10240      64      64 rw---    [ anon ]
00007f67e0552000       4       0       0 -----    [ anon ]
00007f67e0553000   10240      24      24 rw---    [ anon ]
00007f67e0f53000       4       0       0 -----    [ anon ]
00007f67e0f54000   10240      24      24 rw---    [ anon ]
00007f67e1954000       4       0       0 -----    [ anon ]
00007f67e1955000   10240      24      24 rw---    [ anon ]
00007f67e2355000       4       0       0 -----    [ anon ]
00007f67e2356000   10240      20      20 rw---    [ anon ]
00007f67e2d56000       4       0       0 -----    [ anon ]
......
00007f7254ba7000    2044       0       0 -----  libthrift-0.8.0.so
00007f7254da6000      28      20      20 rw---  libthrift-0.8.0.so
00007f7254dad000      80      56       0 r-x--  libboost_filesystem.so.1.42.0
00007f7254dc1000    2048       0       0 -----  libboost_filesystem.so.1.42.0
00007f7254fc1000       4       4       4 rw---  libboost_filesystem.so.1.42.0
00007f7254fc2000       4       0       0 rw---    [ anon ]
00007f7254fc3000       8       8       0 r-x--  libboost_system.so.1.42.0
00007f7254fc5000    2048       0       0 -----  libboost_system.so.1.42.0
00007f72551c5000       4       4       4 rw---  libboost_system.so.1.42.0
00007f72551c6000       4       0       0 rw---    [ anon ]
00007fffb87d0000      88      20      20 rw---    [ stack ]
00007fffb87ff000       4       4       0 r-x--    [ anon ]
ffffffffff600000       4       0       0 r-x--    [ anon ]
----------------  ------  ------  ------
total kB        44349704 3347888 3343404

   从上面的结果上我们可以看出,这个进程的虚拟空间使用的很多的原因是进程动态的申请了很多大块的内存(从进程内存的堆上可以看出),但是这些申请的内存却没有完全被使用.可以想象可能开发
动态的产生了很多数组或对象,但是却没有完全填充.

实验一:动态申请堆内存,但是不使用

测试代码:

#include <iostream>
#include "stdio.h"

int main()
{
    //动态分配的内存在堆区
    char * p = new char [1024*1024*512];
    getchar();
    return 0;
}

测试结果:

jimila@CDYJY-JINGML:内存$ g++ virt.c 
jimila@CDYJY-JINGML:内存$ ./a.out 
jimila@CDYJY-JINGML:内存$ top -n 1 -p `pgrep a.out`
......
#从top命令的结果上看VIRT已经达到了我们申请的512M内存,但是RES却没多少
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                              
22094 jimila    20   0  536812   1056    892 S   0.0  0.0   0:00.00 a.out     
jimila@CDYJY-JINGML:内存$ pmap -x `pgrep a.out`
22094:   ./a.out
#Dirty的内存是我们使用了的
Address           Kbytes     RSS   Dirty Mode  Mapping
0000000000400000       4       4       0 r-x-- a.out
0000000000600000       4       4       4 r---- a.out
0000000000601000       4       4       4 rw--- a.out
00007fdf92c6d000  524292       4       4 rw---   [ anon ] #这一段就是我们动态申请的内存堆,注意想一下上面的内存结构图
00007fdfb2c6e000      88      16       0 r-x-- libgcc_s.so.1
00007fdfb2c84000    2044       0       0 ----- libgcc_s.so.1
00007fdfb2e83000       4       4       4 rw--- libgcc_s.so.1
00007fdfb2e84000    1044      64       0 r-x-- libm-2.19.so
00007fdfb2f89000    2044       0       0 ----- libm-2.19.so
00007fdfb3188000       4       4       4 r---- libm-2.19.so
00007fdfb3189000       4       4       4 rw--- libm-2.19.so
00007fdfb318a000    1772     292       0 r-x-- libc-2.19.so
00007fdfb3345000    2044       0       0 ----- libc-2.19.so
00007fdfb3544000      16      16      16 r---- libc-2.19.so
00007fdfb3548000       8       8       8 rw--- libc-2.19.so
00007fdfb354a000      20      12      12 rw---   [ anon ]
00007fdfb354f000     920     448       0 r-x-- libstdc++.so.6.0.19
00007fdfb3635000    2044       0       0 ----- libstdc++.so.6.0.19
00007fdfb3834000      32      32      32 r---- libstdc++.so.6.0.19
00007fdfb383c000       8       8       8 rw--- libstdc++.so.6.0.19
00007fdfb383e000      84      16      16 rw---   [ anon ]
00007fdfb3853000     140     116       0 r-x-- ld-2.19.so
00007fdfb3a4c000      20      20      20 rw---   [ anon ]
00007fdfb3a72000      12       8       8 rw---   [ anon ]
00007fdfb3a75000       4       4       4 r---- ld-2.19.so
00007fdfb3a76000       4       4       4 rw--- ld-2.19.so
00007fdfb3a77000       4       4       4 rw---   [ anon ]
00007ffefb042000     132      12      12 rw---   [ stack ]
00007ffefb1e4000       8       4       0 r-x--   [ anon ]
ffffffffff600000       4       0       0 r-x--   [ anon ]
---------------- ------- ------- ------- 
total kB          536812    1112     168

实验二:动态申请堆内存,并使用

测试代码:

#include <iostream>
#include <string.h>
#include "stdio.h"

int main()
{
    char * p = new char [1024*1024*512];
    memset(p, 0, 1024*1024*512);
    getchar();
    return 0;
}

测试结果:

jimila@CDYJY-JINGML:内存$ top -n 1 -p `pgrep a.out`
......
#可以看到RES物理内存已经被使用
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                              
11943 jimila    20   0  536812 525140    916 S   0.0  3.2   0:00.30 a.out
jimila@CDYJY-JINGML:内存$ pmap -x `pgrep a.out`
11943:   ./a.out
Address           Kbytes     RSS   Dirty Mode  Mapping
0000000000400000       4       4       0 r-x-- a.out
0000000000600000       4       4       4 r---- a.out
0000000000601000       4       4       4 rw--- a.out
00007fae6d23f000  524292  524292  524292 rw---   [ anon ] #这里的堆内存已经变为Dirty
00007fae8d240000      88      16       0 r-x-- libgcc_s.so.1
00007fae8d256000    2044       0       0 ----- libgcc_s.so.1
00007fae8d455000       4       4       4 rw--- libgcc_s.so.1
00007fae8d456000    1044      64       0 r-x-- libm-2.19.so
00007fae8d55b000    2044       0       0 ----- libm-2.19.so
00007fae8d75a000       4       4       4 r---- libm-2.19.so
00007fae8d75b000       4       4       4 rw--- libm-2.19.so
00007fae8d75c000    1772     292       0 r-x-- libc-2.19.so
00007fae8d917000    2044       0       0 ----- libc-2.19.so
00007fae8db16000      16      16      16 r---- libc-2.19.so
00007fae8db1a000       8       8       8 rw--- libc-2.19.so
00007fae8db1c000      20      12      12 rw---   [ anon ]
00007fae8db21000     920     448       0 r-x-- libstdc++.so.6.0.19
00007fae8dc07000    2044       0       0 ----- libstdc++.so.6.0.19
00007fae8de06000      32      32      32 r---- libstdc++.so.6.0.19
00007fae8de0e000       8       8       8 rw--- libstdc++.so.6.0.19
00007fae8de10000      84      16      16 rw---   [ anon ]
00007fae8de25000     140     116       0 r-x-- ld-2.19.so
00007fae8e01e000      20      20      20 rw---   [ anon ]
00007fae8e044000      12       8       8 rw---   [ anon ]
00007fae8e047000       4       4       4 r---- ld-2.19.so
00007fae8e048000       4       4       4 rw--- ld-2.19.so
00007fae8e049000       4       4       4 rw---   [ anon ]
00007ffc8abd1000     132      12      12 rw---   [ stack ]
00007ffc8abf5000       8       4       0 r-x--   [ anon ]
ffffffffff600000       4       0       0 r-x--   [ anon ]
---------------- ------- ------- ------- 
total kB          536812  525400  524456

实验三:声明局部变量,不使用

测试代码: 我们需要注意 这里 这个问题

//编译前执行一下: ulimit -s 819200
#include <iostream>
#include "stdio.h"

int main()
{
    // 从内存的结构图上我们可以知道,这里的内存应该在栈区.
    char p[1024*1024*512];
    getchar();
    return 0;
}

测试结果:

jimila@CDYJY-JINGML:内存$ top -n 1 -p `pgrep a.out`
......
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                              
 2652 jimila    20   0  536688   1056    884 S   0.0  0.0   0:00.00 a.out    
jimila@CDYJY-JINGML:内存$ pmap -x `pgrep a.out`
2652:   ./a.out
Address           Kbytes     RSS   Dirty Mode  Mapping
0000000000400000       4       4       0 r-x-- a.out
0000000000600000       4       4       4 r---- a.out
0000000000601000       4       4       4 rw--- a.out
00007feb6ad7b000      88      16       0 r-x-- libgcc_s.so.1
00007feb6ad91000    2044       0       0 ----- libgcc_s.so.1
00007feb6af90000       4       4       4 rw--- libgcc_s.so.1
00007feb6af91000    1044      64       0 r-x-- libm-2.19.so
00007feb6b096000    2044       0       0 ----- libm-2.19.so
00007feb6b295000       4       4       4 r---- libm-2.19.so
00007feb6b296000       4       4       4 rw--- libm-2.19.so
00007feb6b297000    1772     264       0 r-x-- libc-2.19.so
00007feb6b452000    2044       0       0 ----- libc-2.19.so
00007feb6b651000      16      16      16 r---- libc-2.19.so
00007feb6b655000       8       8       8 rw--- libc-2.19.so
00007feb6b657000      20      12      12 rw---   [ anon ]
00007feb6b65c000     920     448       0 r-x-- libstdc++.so.6.0.19
00007feb6b742000    2044       0       0 ----- libstdc++.so.6.0.19
00007feb6b941000      32      32      32 r---- libstdc++.so.6.0.19
00007feb6b949000       8       8       8 rw--- libstdc++.so.6.0.19
00007feb6b94b000      84      16      16 rw---   [ anon ]
00007feb6b960000     140     112       0 r-x-- ld-2.19.so
00007feb6bb59000      20      20      20 rw---   [ anon ]
00007feb6bb7f000      12       8       8 rw---   [ anon ]
00007feb6bb82000       4       4       4 r---- ld-2.19.so
00007feb6bb83000       4       4       4 rw--- ld-2.19.so
00007feb6bb84000       4       4       4 rw---   [ anon ]
00007ffdf56f2000  524300      20      20 rw---   [ stack ]#可以看到这次在栈区申请了一块很大的内存,但是没有怎么使用
00007ffe157f3000       8       4       0 r-x--   [ anon ]
ffffffffff600000       4       0       0 r-x--   [ anon ]
---------------- ------- ------- ------- 
total kB          536688    1084     172

实验四:声明局部变量,并使用

测试代码:

#include <iostream>
#include "stdio.h"
#include "string.h"

int main()
{
    char p[1024*1024*512];
    memset(p, 0, 1024*1024*512);
    getchar();
    return 0;
}

测试结果:

jimila@CDYJY-JINGML:内存$ top -n 1 -p `pgrep a.out`
......
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                              
14634 jimila    20   0  536688 525332    884 S   0.0  3.2   0:00.28 a.out 
jimila@CDYJY-JINGML:内存$ pmap -x `pgrep a.out`
14634:   ./a.out
Address           Kbytes     RSS   Dirty Mode  Mapping
0000000000400000       4       4       0 r-x-- a.out
0000000000600000       4       4       4 r---- a.out
0000000000601000       4       4       4 rw--- a.out
00007fdc06c13000      88      16       0 r-x-- libgcc_s.so.1
00007fdc06c29000    2044       0       0 ----- libgcc_s.so.1
00007fdc06e28000       4       4       4 rw--- libgcc_s.so.1
00007fdc06e29000    1044      64       0 r-x-- libm-2.19.so
00007fdc06f2e000    2044       0       0 ----- libm-2.19.so
00007fdc0712d000       4       4       4 r---- libm-2.19.so
00007fdc0712e000       4       4       4 rw--- libm-2.19.so
00007fdc0712f000    1772     264       0 r-x-- libc-2.19.so
00007fdc072ea000    2044       0       0 ----- libc-2.19.so
00007fdc074e9000      16      16      16 r---- libc-2.19.so
00007fdc074ed000       8       8       8 rw--- libc-2.19.so
00007fdc074ef000      20      12      12 rw---   [ anon ]
00007fdc074f4000     920     448       0 r-x-- libstdc++.so.6.0.19
00007fdc075da000    2044       0       0 ----- libstdc++.so.6.0.19
00007fdc077d9000      32      32      32 r---- libstdc++.so.6.0.19
00007fdc077e1000       8       8       8 rw--- libstdc++.so.6.0.19
00007fdc077e3000      84      16      16 rw---   [ anon ]
00007fdc077f8000     140     112       0 r-x-- ld-2.19.so
00007fdc079f1000      20      20      20 rw---   [ anon ]
00007fdc07a17000      12       8       8 rw---   [ anon ]
00007fdc07a1a000       4       4       4 r---- ld-2.19.so
00007fdc07a1b000       4       4       4 rw--- ld-2.19.so
00007fdc07a1c000       4       4       4 rw---   [ anon ]
00007ffdfe59d000  524300  524296  524296 rw---   [ stack ] #这里和上面的对比一看就明白了
00007ffe1e5a5000       8       4       0 r-x--   [ anon ]
ffffffffff600000       4       0       0 r-x--   [ anon ]
---------------- ------- ------- ------- 
total kB          536688  525360  524448

实验五:申明全局变量,不初始化

测试代码:

#include <iostream>
#include "stdio.h"

char p[1024*1024*512];
int main()
{
    getchar();
    return 0;
}

测试结果:

jimila@CDYJY-JINGML:内存$ top -n 1 -p `pgrep a.out`
......
 PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                              
29172 jimila    20   0  536808   1056    892 S   0.0  0.0   0:00.00 a.out 
jimila@CDYJY-JINGML:内存$ pmap -x `pgrep a.out`
29172:   ./a.out
Address           Kbytes     RSS   Dirty Mode  Mapping
0000000000400000       4       4       0 r-x-- a.out
0000000000600000       4       4       4 r---- a.out
0000000000601000       4       4       4 rw--- a.out
0000000000602000  524288       0       0 rw---   [ anon ]#这里就是进程bss区
00007f718fed6000      88      16       0 r-x-- libgcc_s.so.1
00007f718feec000    2044       0       0 ----- libgcc_s.so.1
00007f71900eb000       4       4       4 rw--- libgcc_s.so.1
00007f71900ec000    1044      64       0 r-x-- libm-2.19.so
00007f71901f1000    2044       0       0 ----- libm-2.19.so
00007f71903f0000       4       4       4 r---- libm-2.19.so
00007f71903f1000       4       4       4 rw--- libm-2.19.so
00007f71903f2000    1772     264       0 r-x-- libc-2.19.so
00007f71905ad000    2044       0       0 ----- libc-2.19.so
00007f71907ac000      16      16      16 r---- libc-2.19.so
00007f71907b0000       8       8       8 rw--- libc-2.19.so
00007f71907b2000      20      12      12 rw---   [ anon ]
00007f71907b7000     920     448       0 r-x-- libstdc++.so.6.0.19
00007f719089d000    2044       0       0 ----- libstdc++.so.6.0.19
00007f7190a9c000      32      32      32 r---- libstdc++.so.6.0.19
00007f7190aa4000       8       8       8 rw--- libstdc++.so.6.0.19
00007f7190aa6000      84      16      16 rw---   [ anon ]
00007f7190abb000     140     112       0 r-x-- ld-2.19.so
00007f7190cb4000      20      20      20 rw---   [ anon ]
00007f7190cda000      12       8       8 rw---   [ anon ]
00007f7190cdd000       4       4       4 r---- ld-2.19.so
00007f7190cde000       4       4       4 rw--- ld-2.19.so
00007f7190cdf000       4       4       4 rw---   [ anon ]
00007ffc5eac1000     132      12      12 rw---   [ stack ]
00007ffc5eb99000       8       4       0 r-x--   [ anon ]
ffffffffff600000       4       0       0 r-x--   [ anon ]
---------------- ------- ------- ------- 
total kB          536808    1076     164

目录