作者: uNDeaD
Email: someonebw@gmail.com
Blog: http://blog.youkuaiyun.com/undead
转载请注明出处
最近观察生产平台上面的应用,发现应用进程所占用的内存是只增,不减,于是想深入看看,具体造成的原因。
PID USERNAME SIZE RSS STATE PRI NICE TIME CPU PROCESS/NLWP
5506 bwisp 1631M 1501M sleep 53 2 31:27:16 4.1% bwisp/275
标红的地方就是的
程序运行时间也就是5.12日开始的,到今天也没有几天,初始才300M;现在内存已经占用了1.6G
-bash-3.00$ pmap -x 5506|more
5506: /sims/bwisp/bin/bwisp -d
Address Kbytes RSS Anon Locked Mode Mapped File
0000000100000000 512 480 - - r-x-- bwisp
000000010017E000 112 24 24 - rwx-- bwisp
000000010019A000 1616168 1529064 1488736 - rwx-- [ heap ]//确实很大
FFFFFFFF4E600000 88 88 - - r-x-- groupsend.so
FFFFFFFF4E714000 24 24 24 - rwx-- groupsend.so
FFFFFFFF4E800000 56 48 - - r-x-- libgradequery.so
FFFFFFFF4E90C000 16 16 16 - rwx-- libgradequery.so
FFFFFFFF4EA00000 64 64 - - r-x-- libsmsorder.so
FFFFFFFF4EB0E000 8 8 8 - rwx-- libsmsorder.so
确实是heap段,占用了大部分的内存。
按理说,进程new内存后,都会用free来进行释放,为什么heap段还是如此之大呢?问题产生了!
两种可能性
1。内存泄漏
2。操作系统本身的实现机制就是如此
通过实验来验证自己的想法!
实验用程序如下:
/*
* main.cpp
*
* Created on: 2010-4-9
* Author: Administrator
*/
//#include "SOTest.h"
#include <iostream>
#include <queue>
#include <string>
#include <dlfcn.h>
#include <link.h>
void *libSOTest = NULL;
void (*loadFun)(void) = NULL;
void (*unLoadFun)(void) = NULL;
void (*parseFun)(std::string &, std::string &, std::string &) = NULL;
bool LoadSO()
{
if((libSOTest = dlopen("./libSOTest.so", RTLD_NOW | RTLD_GLOBAL)) != 0)
{
loadFun = (void (*)(void)) dlsym(libSOTest, "Load");
if(dlerror())
{
std::cout << "Load error :" << dlerror() << std::endl;
}
//
unLoadFun = (void (*)(void)) dlsym(libSOTest, "Unload");
if(dlerror())
{
std::cout << "Unload error :" << dlerror() << std::endl;
}
//
parseFun = (void (*)(std::string &, std::string &, std::string &)) dlsym(libSOTest, "Parse");
if(dlerror())
{
std::cout << "Parse error :" << dlerror() << std::endl;
}
return true;
}
else
{
std::cout << "LoadSO dlopen failed..." << std::endl;
return false;
}
}
void UnloadSO()
{
if (libSOTest != NULL)
{
dlclose(libSOTest);
libSOTest = NULL;
}
}
int main(int argc, const char* argv[])
{
// std::string v2 = "12345678";
//
// std::string v = fun(v2);
//
// std::cout << v << std::endl;
//
// std::cout << "call que..." << std::endl;
//
//
// CA que;
//
//
//
// for(int i = 0; i < 10; i++)
// {
// char Data[64];
//
// memset(Data,0,sizeof(Data));
// sprintf(Data,"item_%02d = %d ",i, i);
//
// std::cout << "call push()" << " " << Data << std::endl;
//
// std::string v2 = Data;
//
// que.push(v2);
// }
//
// std::cout << que.size() << std::endl;
//
// v = "";
//
// while(que.size() > 0)
// {
// que.pop(v);
//
// std::cout << v << std::endl;
// }
while(true)
{
char in[256];
memset(in,0,sizeof(in));
gets(in);
std::string in1 = in;
std::cout << "in param:" << in1 << std::endl;
if (in1 == "exit")
{
break;
}
if (in1 == "new")
{
void * pData[10000];
for(int i = 0; i < 10000; i++)
{
char *p = new char[10240];
if (p != NULL)
{
p[10240 - 1] = 'a';
pData[i] = p;
}
else
{
std::cout << "new return null" << std::endl;
break;
}
}
for(int j = 0; j < 10000; j++)
{
if (pData[j] != NULL)
{
delete [] pData[j];
}
}
std::cout << "new end" << std::endl;
}
if (in1 == "load")
{
LoadSO();
//
loadFun();
std::cout << "load end" << std::endl;
}
if (in1 == "unload")
{
unLoadFun();
UnloadSO();
std::cout << "unload end" << std::endl;
}
if (in1 == "loadfile")
{
std::string str1 = "loadfile";
std::string str2 = "./1.txt";
std::string str3 = "";
parseFun(str1, str2, str3);
std::cout << "loadfile end" << std::endl;
}
if (in1 == "info")
{
std::string str1 = "info";
std::string str2 = "";
std::string str3 = "";
parseFun(str1, str2, str3);
std::cout << "info end return :" << str3 << std::endl;
}
}
return 1;
}
-bash-3.00$ ./main3
load //加载so
in param:load
CenterBuilder(): new Center()
libSOTest.so Load()
load end
loadfile //加载1.txt文本
in param:loadfile
libSOTest.so Parse() loadfile ./1.txt
loadfile end
unload //卸载so
in param:unload
libSOTest.so Unload()
~CenterBuilder(): delete __pCenter
0 21643797 21643797 //后面两个数的差值,new的次数,free的次数
unload end
root@Bwisp-WT-01 # pmap -x 3547
3547: ./main3
Address Kbytes RSS Anon Locked Mode Mapped File
0000000100000000 16 16 - - r-x-- main3
0000000100102000 8 8 8 - rwx-- main3
0000000100104000 3056 2784 1544 - rwx-- [ heap ]
0000000100400000 249856 241664 241664 - rwx-- [ heap ] //so卸载后,free后,heap段内存依旧这么多
FFFFFFFF7DF00000 8 8 8 - rwx-- [ anon ]
FFFFFFFF7E200000 64 64 48 - rwx-- [ anon ]
FFFFFFFF7E300000 8 8 - - r-x-- libc_psr.so.1
FFFFFFFF7E400000 40 16 - - r-x-- libgcc_s.so.1
FFFFFFFF7E508000 16 16 16 - rwx-- libgcc_s.so.1
FFFFFFFF7E600000 8 8 8 - rwx-- [ anon ]
FFFFFFFF7E700000 944 824 - - r-x-- libc.so.1
FFFFFFFF7E8EC000 64 64 56 - rwx-- libc.so.1
FFFFFFFF7E8FC000 8 8 8 - rwx-- libc.so.1
FFFFFFFF7EA00000 640 200 - - r-x-- libm.so.2
FFFFFFFF7EB9E000 40 24 8 - rwx-- libm.so.2
FFFFFFFF7EC00000 64 48 - - r-x-- libCrun.so.1
FFFFFFFF7ED0E000 16 16 16 - rwx-- libCrun.so.1
FFFFFFFF7ED12000 16 8 8 - rwx-- libCrun.so.1
FFFFFFFF7EE00000 1808 680 - - r-x-- libCstd.so.1
FFFFFFFF7F0C2000 64 64 56 - rwx-- libCstd.so.1
FFFFFFFF7F0D2000 8 8 8 - rwx-- libCstd.so.1
FFFFFFFF7F100000 8 8 8 - rwx-- [ anon ]
FFFFFFFF7F200000 856 472 - - r-x-- libstdc++.so.6
FFFFFFFF7F3D4000 248 144 48 - rwx-- libstdc++.so.6
FFFFFFFF7F500000 24 16 16 - rwx-- [ anon ]
FFFFFFFF7F600000 208 208 - - r-x-- ld.so.1
FFFFFFFF7F734000 16 16 16 - rwx-- ld.so.1
FFFFFFFF7F738000 8 8 8 - rwx-- ld.so.1
FFFFFFFF7FFEA000 88 80 56 - rw--- [ stack ]
---------------- ---------- ---------- ---------- ----------
total Kb 258208 247488 243608 -
通过pmap可以看到,so确实是卸载了,但是heap段没有释放
接下来可以通过gcore来看看,heap段的具体信息
gcore 3547 //生成进程的core
mdb core.3547
root@Bwisp-WT-01 # mdb core.3547
Loading modules: [ libc.so.1 ld.so.1 ]
> ::mappings
BASE LIMIT SIZE NAME
100000000 100004000 4000 a.out
100102000 100104000 2000 a.out
100104000 100400000 2fc000
100400000 10f800000 f400000 [ heap ]
ffffffff7df00000 ffffffff7df02000 2000
ffffffff7e200000 ffffffff7e210000 10000
ffffffff7e300000 ffffffff7e302000 2000 /platform/sun4u-us3/lib/sparcv9/libc_psr.so.1
ffffffff7e400000 ffffffff7e40a000 a000 /usr/local/64/lib/libgcc_s.so.1
ffffffff7e508000 ffffffff7e50c000 4000 /usr/local/64/lib/libgcc_s.so.1
ffffffff7e600000 ffffffff7e602000 2000
ffffffff7e700000 ffffffff7e7ec000 ec000 /lib/sparcv9/libc.so.1
ffffffff7e8ec000 ffffffff7e8fc000 10000 /lib/sparcv9/libc.so.1
ffffffff7e8fc000 ffffffff7e8fe000 2000 /lib/sparcv9/libc.so.1
ffffffff7ea00000 ffffffff7eaa0000 a0000 /lib/sparcv9/libm.so.2
ffffffff7eb9e000 ffffffff7eba8000 a000 /lib/sparcv9/libm.so.2
ffffffff7ec00000 ffffffff7ec10000 10000 /usr/lib/sparcv9/libCrun.so.1
ffffffff7ed0e000 ffffffff7ed12000 4000 /usr/lib/sparcv9/libCrun.so.1
ffffffff7ed12000 ffffffff7ed16000 4000 /usr/lib/sparcv9/libCrun.so.1
ffffffff7ee00000 ffffffff7efc4000 1c4000 /usr/lib/sparcv9/libCstd.so.1
ffffffff7f0c2000 ffffffff7f0d2000 10000 /usr/lib/sparcv9/libCstd.so.1
ffffffff7f0d2000 ffffffff7f0d4000 2000 /usr/lib/sparcv9/libCstd.so.1
ffffffff7f100000 ffffffff7f102000 2000
ffffffff7f200000 ffffffff7f2d6000 d6000 /usr/local/64/lib/libstdc++.so.6
ffffffff7f3d4000 ffffffff7f412000 3e000 /usr/local/64/lib/libstdc++.so.6
ffffffff7f500000 ffffffff7f506000 6000
ffffffff7f600000 ffffffff7f634000 34000 /lib/sparcv9/ld.so.1
ffffffff7f734000 ffffffff7f738000 4000 /lib/sparcv9/ld.so.1
ffffffff7f738000 ffffffff7f73a000 2000 /lib/sparcv9/ld.so.1
ffffffff7ffea000 ffffffff80000000 16000 [ stack ]
>
> 100400000,f/apn //可以看到,数据还是在heap的内存中
0x100400000: 0x100400000: 0x3133343239383439
0x100400008: 0x3232370000000000
0x100400010: 0x3133343239383439
0x100400018: 0x3232390000000000
0x100400020: 0x3133343239383439
0x100400028: 0x3233300000000000
0x100400030: 0x3133343239383439
0x100400038: 0x3233390000000000
0x100400040: 0x3133343239383439
0x100400048: 0x3234310000000000
0x100400050: 0x3133343239383439
0x100400058: 0x3234320000000000
0x100400060: 0x3133343239383439
0x100400068: 0x3234350000000000
0x100400070: 0x3133343239383439
0x100400078: 0x3235330000000000
0x100400080: 0x3133343239383439
0x100400088: 0x3235350000000000
0x100400090: 0x3133343239383439
0x100400098: 0x3235380000000000
0x1004000a0: 0x3133343239383439
0x1004000a8: 0x3235390000000000
0x1004000b0: 0x3133343239383439
0x1004000b8: 0x3236300000000000
0x1004000c0: 0x3133343239383439
0x1004000c8: 0x3236380000000000
0x1004000d0: 0x3133343239383439
0x1004000d8: 0x3236390000000000
0x1004000e0: 0x3133343239383439
0x1004000e8: 0x3237300000000000
0x1004000f0: 0x3133343239383439
0x1004000f8: 0x3237360000000000
0x100400100: 0x3133343239383439
0x100400108: 0x3237370000000000
0x100400110: 0x3133343239383439
0x100400118: 0x3237380000000000
0x100400120: 0x3133343239383439
0x100400128: 0x3237390000000000
0x100400130: 0x3133343239383439
0x100400138: 0x3238320000000000
实验验证了我们的想法,并不是内存泄漏,new和free的次数是一致的,所以排除了这个可能!
证实了观点2,为操作系统的机制造成的!
如下:摘录自Solaris 内核结构