linux系统编程-内存管理day03

  • 总结了8.6~8.7的内容

调试内存分配

程序可以设置MALLOC_CHECK_环境变量来开启存储系统额外的调试功能。

  • 这个额外的调试检查是以降低内存分配的效率为代价的。
  • 这个开销在开发应用的调试阶段是非常值得的,因为仅仅一个环境变量就能控制调试,不必重新编译程序。
    可以简单的执行如下指令:
$ MALLOC_CHECK_=1 ./rudder

MALLOC_CHECK_有三种设定:
MALLOC_CHECK_=0, 存储系统会忽略所有错误
MALLOC_CHECH_=1, 信息会被输出到标准错误输出stderr.
MALLOC_CHECK_=2, 进程会立即通过abort( )终止。

获得统计数据

  1. mallinfo( )函数用来获得关于动态存储分配系统的统计数据:
#include 
struct mallinfo mallinfo(void);
  • 用法:
struct mallinfo m;
m = mallinfo( );
printf("free chunks: %d \n", m.ordblks);
  1. stats( )函数,将跟内存相关的统计数据打印到标准错误输出(stderr):
#include 
void malloc_stats(void);

基于的分配

之前的几节关于动态内存分配机制都是使用存储器映射来实现的(因为堆和匿名映射本来就是动态的,所以很自然地想到用它们来分配动态内存).
另一个在程序地址空间中常用的结构,,是用来存放程序的自动变量的。

  • 在很多系统中,基于栈的分配没有被定义,或者性能很差。但是在Linux系统中,基于栈的分配(alloca( ))却是一个非常好用但没有被人们认识到的工具,在各种架构下,通过alloca( )进行内存分配就和增加栈指针一样简单,比malloc( )性能好很多。对于linux下较小的内存分配,alloca( )能收获令人激动的性能,故学习它是很有必要的。
  1. alloca( )函数:
#include 
void *alloca(size_t size);

调用alloca( )时,成功时会返回一个指向size字节大小的内存指针。

  • 这块内存是在栈中的,当调用它的函数(例如main函数)返回时,这块内存将被自动释放
  • 用法与malloc( )一样,但是不用自己释放(也不能自己释放)。

注意不能使用由alloca( )得到的内存来作为一个函数调用的参数,因为分配到的内存块会被当做参数保存在函数的栈中。例如:以下就是错误的

/* Do not do this! */
ret = foo (x, alloca(100));
  1. strdupa( ) 和 strndupa( )
    alloca( )常见的一个用法是来临时复制一个字符串。例如:
char *dup;
dup = alloca(strlen(song) + 1);
strcpy(dup, song);
/* 使用dup */
return; /* dup is automatically freed */

linux专门提供了strdupa( )来将一个给定的字符串复制到栈中:

#define _GNU_SOURCE
#include 
char *strdupa (const char *s);
char *strndupa (const char *s, size_t n);
  • 调用strdupa( )会返回一个s的拷贝。strndupa( )将拷贝s中的(前)n个字符。
  • POSIX并没有定义alloca( ), strdupa( ), strndupa( ). 考虑到可移植性,不鼓励使用这些函数。
  • 然而在linux上,alloca( )以及由它衍生的一些函数却表现的非常好,可以通过简单的移动栈指针来代替其它一些复杂动态分配内存方法。
  1. 变长数组VLAs
    VLAs用与alloca( )相似的方法避免了动态存储分配所产生的负载。例如:
for (i  = 0; i < n; ++i) {
    char foo[i+1];
    /* use 'foo' ... */
}

在上面的例子中,在每次循环中,foo都被动态的创建,并在这轮循环结束时自动释放

  • 如果我们使用alloca( )来代替VLAs,那么内存空间将直到函数返回时才会被释放。
  • alloca( )和变长数组的主要区别在于:前者获得的内存在函数执行过程中始终存在,而通过后者获得的内存在出了作用域后便释放了。
  • 为了安全起见,在一个固定的函数中只应使用其中之一。

你可能感兴趣的:(linux系统编程-内存管理day03)