Skip to content

Latest commit

 

History

History
274 lines (230 loc) · 8.88 KB

200610172023.txt.md

File metadata and controls

274 lines (230 loc) · 8.88 KB

4.4 Solaris上free()的内存如何还给OS

http://scz.617.cn/unix/200610172023.txt

Q:

在一台SPARC/Solaris 9上man free,看到如下一段话:

After free() is executed, this space is made available for further alloca- tion by the application, though not returned to the system. Memory is ret- urned to the system only upon termination of the application.

现在我想强制free()的内存还给OS,怎么办。

D: valent@SMTH 2006-10-15

AIX为了解决这种问题,提供了一个环境变量:

MALLOCDISCLAIM=true

代价是进程会遇到更多的Page Fault,性能相应有所损失。还可以调用mallopt使用 M_DISCLAIM命令达到类似效果。

D: scz@nsfocus 2006-10-17

受valent的启发,Goolge了一圈,参考资源如下:


[1] For AIX

Malloc Disclaim
http://moka.ccr.jussieu.fr/doc_link/C/a_doc_lib/aixprggd/genprogc/malloc_disclaim.htm
(介绍了MALLOCDISCLAIM=true)

http://moka.ccr.jussieu.fr/doc_link/en_US/a_doc_lib/libs/basetrf1/malloc.htm
(介绍了mallopt、M_DISCLAIM、PSALLOC=early)

http://publib.boulder.ibm.com/infocenter/pseries/v5r3/topic/com.ibm.aix.genprogc/doc/genprogc/malloc_disclaim.htm
(介绍了MALLOCOPTIONS=disclaim,从AIX 5L Version 5.3开始不应继续使用MALLOCDISCLAIM环境变量)

disclaim Subroutine
http://publib.boulder.ibm.com/infocenter/pseries/v5r3/topic/com.ibm.aix.basetechref/doc/basetrf1/disclaim.htm

System Memory Allocation Using the malloc subsystem
http://publib.boulder.ibm.com/infocenter/pseries/v5r3/topic/com.ibm.aix.genprogc/doc/genprogc/sys_mem_alloc.htm
(较为详细地介绍了malloc)

Developing and Porting C and C++ Applications on AIX
http://www.redbooks.ibm.com/redbooks/pdfs/sg245674.pdf
(介绍了disclaim、MALLOCDISCLAIM以及/etc/environment的限制)

[2] For Solaris

bsdmalloc(3MALLOC)
http://docs.sun.com/app/docs/doc/816-5168/6mbb3hr5a?a=view
http://bama.ua.edu/cgi-bin/man-cgi?bsdmalloc+3MALLOC
(介绍了-lbsdmalloc,性能最好但空间利用率低)

malloc(3C)
http://docs.sun.com/app/docs/doc/816-5168/6mbb3hrgp?a=view
http://bama.ua.edu/cgi-bin/man-cgi?malloc+3C
(注意跟下面那个链接的区别,在bsdmalloc(3MALLOC)与malloc(3MALLOC)之间搞平衡)

malloc(3MALLOC)
http://docs.sun.com/app/docs/doc/816-5168/6mbb3hrgq?a=view
http://bama.ua.edu/cgi-bin/man-cgi?malloc+3MALLOC
(介绍了mallopt、M_KEEP、-lmalloc,性能最差但空间利用率高)

mapmalloc(3MALLOC)
(介绍了-lmapmalloc,实现与手册描述不符,参后文讨论)

[3] For Linux

Advanced Memory Allocation - Gianluca Insolvibile [2003-05-01]
http://www.linuxjournal.com/article/6390
(介绍了mallopt、MALLOC_TRIM_THRESHOLD、malloc_trim、mallinfo)

/usr/include/malloc.h
(有很多man手册里未提到的细节)

"free" does not frees memory ? - Baruch Even [2006-10-03]
http://www.mail-archive.com/[email protected]/msg45577.html

Google for "madvise MADV_DONTNEED MADV_FREE"

根据[2],虽然Solaris没有像AIX那么善解人意,但至少有了一个可选方案,即调用 malloc(3MALLOC),而不是调用malloc(3C),换句话说,用-lmalloc应该就可以解决 问题。在这个思路下我写了一个测试程序,用-lmalloc链接,最终还用ldd确认;遗 憾的是,在我的一台SPARC/Solaris 9上并没有看到期待中的效果。

不得已,决定有条件、有限度地自己干预一下Solaris的堆管理机制,动用系统调用 sbrk();此时无论是否用-lmalloc链接,第一个memtrimtest进程都不会干挠到第二 个memtrimtest进程。为减少不必要的干挠,请以root身份进行测试。


/*

  • For x86/Linux Kernel 2.6.16.5
  • gcc -DLinux -Wall -pipe -O3 -s -o memtrimtest memtrimtest.c
  • For SPARC/Solaris 9
  • gcc -DSparc -Wall -pipe -O3 -s -o memtrimtest memtrimtest.c
  • gcc -DSparc -Wall -pipe -O3 -s -o memtrimtest memtrimtest.c -lmalloc
  • gcc -Wall -pipe -O3 -s -o memtrimtest memtrimtest.c -lmapmalloc
  • mcs -d memtrimtest / #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> /
  • for mallopt() */ #include <malloc.h>

int main ( int argc, char * argv[] ) { int ret = EXIT_FAILURE; unsigned char **parray = NULL; unsigned int i, xint = 587, yint = 1024 * 1024 * 5, zint = 0; #if defined(Sparc) || defined(Solaris) void *begin, *end; #endif

#if 0 fprintf( stderr, "Usage: %s [xint] [yint] [zint]\n", argv[0] ); #endif if ( argc > 1 ) { if ( 0 == ( xint = ( unsigned int )strtoul( argv[1], NULL, 0 ) ) ) { fprintf( stderr, "Checking your \n" ); goto main_exit; } } if ( argc > 2 ) { if ( 0 == ( yint = ( unsigned int )strtoul( argv[2], NULL, 0 ) ) ) { fprintf( stderr, "Checking your \n" ); goto main_exit; } } if ( argc > 3 ) { zint = ( unsigned int )strtoul( argv[3], NULL, 0 ); } #if 0 mallopt( M_KEEP, 0 ); #endif #if defined(Sparc) || defined(Solaris) if ( ( void * )-1 == ( begin = sbrk( 0 ) ) ) { perror( "sbrk for begin" ); goto main_exit; } #endif /* * 刻意使用calloc()而不是malloc() / if ( NULL == ( parray = ( unsigned char ** )calloc( xint, sizeof( unsigned char * ) ) ) ) { perror( "calloc for parray" ); goto main_exit; } for ( i = 0; i < xint; i++ ) { / * 刻意使用calloc()而不是malloc() / if ( NULL == ( parray[i] = ( unsigned char * )calloc( yint, 1 ) ) ) { fprintf ( stderr, "calloc for parray[%u] error: %s\n", i, strerror( errno ) ); goto main_exit; } parray[i][yint-1] = i; } / end of for / / * 产生阻塞 / fprintf( stderr, "Press any key [0]" ); getchar(); for ( i = 0; i < xint; i++ ) { #if 1 free( parray[i] ); #else realloc( parray[i], 0 ); #endif parray[i] = NULL; } / end of for / free( parray ); parray = NULL; #if defined(Sparc) || defined(Solaris) if ( ( void * )-1 == ( end = sbrk( 0 ) ) ) { perror( "sbrk for end" ); goto main_exit; } if ( ( void * )-1 == sbrk( begin - end ) ) { perror( "sbrk for begin minus end" ); goto main_exit; } #endif if ( !zint ) { / * 产生阻塞 */ fprintf( stderr, "Press any key [1]" ); getchar(); } ret = EXIT_SUCCESS;

main_exit:

if ( NULL != parray )
{
    for ( i = 0; i < xint; i++ )
    {
        if ( NULL != parray[i] )
        {

#if 1 free( parray[i] ); #else realloc( parray[i], 0 ); #endif parray[i] = NULL; } } /* end of for / free( parray ); parray = NULL; } return( ret ); } / end of main */

这是在非常特定的前提下动用sbrk()直接干预Solaris堆管理机制,不是正经解决方 案。事实上这样做并不安全,动用sbrk()后,绕过了堆管理结构,使得堆管理结构与 虚拟内存(物理内存+SWAP)之间不再同步,sbrk( begin - end )释放了虚拟内存,但 堆管理结构并不知道这一点,如果后面还有malloc()操作,并且读写其返回的堆区, 很可能出事。本例也就是马上要结束进程了,否则真不敢乱用sbrk( begin - end ) 收缩堆区。

valent提供的信息是AIX上同类问题的通用解决方案,不知Solaris是否有类似的通用 解决方案。至少在这次测试中,-lmalloc无效。

我在x86/Linux Kernel 2.6.16.5上测试的时候,无论是否动用sbrk(),都未出现第 一个memtrimtest进程干挠到第二个memtrimtest进程的现象,这是好事。

A: sanshao@SMTH 2006-10-18

参mapmalloc(3MALLOC),虽然manual里声称:

There is no reclaiming of memory.

但实际上源码中每次free()都试图调用一下defrag...(),其中会有munmap()。以前 述memtrimtest.c为例,用-lmapmalloc链接即可解决问题:

gcc -Wall -pipe -O3 -s -o memtrimtest memtrimtest.c -lmapmalloc

在SPARC/Solaris 9上测试通过。