Solaris系统的进程内存管理库

 

Solaris系统的进程内存管理库

 

 

 

问题描述

有如下测试程序:

int main()

{

char* p[1000];

int j=200;

char tmp[255];

for(int i=0; i

      p[i]=new char[1024*1024*5]; // 5MB

 

 

printf(“pid=%d, wait input/n”, getpid());

sscanf(“%s”, tmp); // (1)

 

 

for(int i=0; i

    delete[] p[i]

 

 

printf(“pid=%d, wait input/n”, getpid());

sscanf(“%s”, tmp); //(2)

return 0;

}

以上代码,在一台Redhat8计算机上编译运行(修改j值,使得程序尽可能申请更多内存),发现当程序运行到(1)处,再开一个shell运行该进程,发现居然还能申请到内存。

在另外一台Solaris7运行程序(修改j为最大可能的值,让程序尽可能多申请内存,并用top监视该进程;发现进程调用free释放所申请的内存后,也就是程序运行到(2)后,内存未归还给操作系统,以至于其他进程申请不到足够的内存。

不考虑两台计算机的内存配置,就Solaris表现出来的行为,还是让人诧异,Why

 

 

Solaris的进程内存管理包

Solaris提供来若干内存分配的函数库以供选择. 这些库是标准C库,malloc, bsdmalloc, mapmalloc. 此外还有mtmalloc用于高性能多线程应用程序, watchmalloc用于内存调试. Solaris 9 4/03还提供libumem用于提供快速, 可扩展,对象缓存的内存分配技术来支持多线程应用程序, libumem还对调试提供大量支持, 包括内存泄漏检测, 缓冲区溢出, 多次释放, 使用未初始化数据, 使用已经释放的数据, 以及大量常见编程错误.

 

 

标准C

对应libc.so, 这是标准C库提供的, Solaris默认的内存管理库. 该库中的free函数在释放内存的时候, 内存并不归还给操作系统, 而是留给下次该进程申请内存使用, 从而可能减少向操作系统申请内存的次数. 直接进程退出后, 内存才会还给操作系统.

 

 

malloc

当空间比性能更重要的时候, 我们可以采用malloc. 这个库提供的函数与默认库的基本相同,但是进程释放的内存被显式的标记为unavailable(尽管可以通过mallopt函数来修改该行为).要使用这些函数, 编译程序必需用 -lmalloc参数. 尽管这些函数在中声明, 我们仍然必需include 来引入其他函数.
     
除了提供内存分配和释放函数(malloc, realloc, calloc, free), malloc库还提供两个函数: malloptmallinfo。mallopt函数用来控制内存分配算法的某些参数选项. mallinfo函数获取内存空间使用情况信息.

 

bsdmalloc

当性能比内存空间更重要的时候, 我们应该采用bsdmalloc库来管理内存. 这个库提供三个函数, 这三个函数与标准C库提供的不兼容. 因此尽量不要使用bsdmalloc, 除非内存分配和释放被证明是应用程序最主要的性能瓶颈.这三个函数是malloc, realloc, free. 要使用这三个函数, 编译选项要用-lbsdmalloc参数.

 

 

 

 mapmalloc

 

内存分配函数用来申请堆内存(alloca例外), 如果请求的内存超过进程的堆空间, 那么就调用sbrk系统调用; mapmmalloc中的函数则调用mmap系统调用. 要使用mapmalloc, 编译选项要用 -lmaplloc.

  

 

比较malloc

比较bsdmalloc, malloc, libc库中的malloc函数

n         bsdmalloc库函数牺牲空间和SCD(Sparc Compliance Definition)兼容性来获取较高的性能

n         malloc库函数性能低一些, 但是节省空间

n         标准的, SCD兼容的标准C库在内存管理上, 对性能和空间进行来折衷. 如果缺乏有说服力的原因, 大部分程序应该用libc库的内存管理.

 
Rich Teer在<>第三章中编写了一个测试程序来比较这些内存管理库的性能。该程序分配和释放了大量大小不一的内存块。下表是测试程序在Sun Blade 100的计算机上运行的结果.

 

 

Version of malloc         Time       Size
libc                      3          15752
malloc                    13         20768
bsdmalloc                 2          21000
mapmalloc                 910        1000
watchmalloc               110069     15776

 

 

上面的Time表示程序运行的时间(秒为单位), Size表示进程占用的虚存(KB为单位). 我们可以通过运行

下面这个命令来获得Size.

  $ps -eo vsz,comm | grep malloc

  15752 ./malloc

需要特别注意的是, mapmallocwatchmalloc比起其他版本, malloc要慢得多. watchmalloc对性能的影响尤其严重, 需要30多个小时才能运行完毕, libc只需要3, 因此仅仅用于调试.

 

 

解决问题

经过对几个库的测试,发现mapmalloc库在调用free后能立刻把内存归还给操作系统。而且幸运的是,我们的程序不需要重新链接, 只需简单设置一下LD_PRELOAD环境变量就可以了.
LD_PRELOAD: 一个以空格隔开的shared objects列表, 运行时链接器(runtimer linker)会解析该列表. 在程序开始执行后和加载该程序引用的共享库之前, 列表中指定的共享库会被链接进来

LD_PRELOAD: Provides a  whitespace-separated  list  of  shared objects  that are to be interpreted by the runtime linker. The specified shared  objects  are  linked after the program is executed but before any other shared objects that the program references.

 

最后的问题

 

 

 在开头的测试中, Redhat上该进程申请最多能够申请的内存,保持不释放;再运行该进程,居然还能申请到这么多内存。怎么回事?谁解释一下,3x。

你可能感兴趣的:(Solaris系统的进程内存管理库)