我爱编程

linux系统编程-内存管理day02

2018-05-25  本文已影响0人  桔子满地

数据段的管理

在老版本的Unix系统中,堆和栈还在同一个段中。

在现代系统中,数据段存在于它自己的内存映射中,仍用中断点来标记映射的结束地址。
提供以下函数:

#include <unistd.h>
int brk(void *end);
void *sbrk(intptr_t increment);

匿名存储器映射

首先来看看伙伴内存分配算法
glibc的内存分配使用了数据段和内存映射。
实现malloc( )最经典方法就是将数据段分为一系列的大小为2的幂的块,返回最小的符合要求的那个块来满足请求。 释放只是简单的将这块区域标记为未使用。

匿名内存映射(anonymous memory mapping)
因为伙伴内存分配算法存在可能被“栓”住的问题,glibc对于较大的分配,并不使用堆而是创建一个匿名内存映射来满足要求。

创建匿名存储器映射
匿名存储器映射与内存映射很像:

/* for memory map */
#include <sys/mman.h>
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *start, size_t length);
void *p;
p = mmap(NULL, 512*1024, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (p == MAP_FAILED)
  perror("mmap");
else
  /* 'p' points at 512 KB of anonymous memory ... */

参数含义:

int ret;
ret  = munmap(p, 512*1024);
if (ret)
  perror("munmap");

映射到/dev/zero

其他Unix系统(例如BSD),并没有MAP_ANONYMOUS标记。它们使用特殊的设备文件/dev/zero来实现了一个类似的解决方案。这个设备文件提供了和匿名内存相同的语义。

void *p;
int fd;
/* open /dev/zero for reading and writing */
fd = open("/dev/zero", O_RDWR);
if (fd < 0) {
  perror("open");
  return -1;
}
/* map [0, page_size) of /dev/zero */
p = mmap(NULL, getpagesize( ), PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (p == MAP_FAILED) {
  perror("mmap");
  if (close(fd))
    perror("close");
  return -1;
}
/* close /dev/zero, no longer needed */
if (close(fd))
  perror("close");
/* 'p' points at one page of memory, use it ... */

采用这种映射方式的存储器也是用munmap( )来取消映射的。
然而这种方法因为要打开和关闭设备文件,所以会有额外的开销。因此匿名内存映射是一种较块的方法。

高级存储器分配

许多存储分配操作都是为内核的参数所控制的(例如malloc( )时,是从数据段分配还是从匿名内存映射,这个临界值,是内核参数),但是程序员可以修改这些参数!

  1. mallopt( )函数:
    调用mallopt( )会将由param确定的存储管理相关的参数设为value。
    linux目前支持六种param值,被定义在<malloc.h>中:
    • M_CHECK_ACTION
    • M_MMAP_MAX
    • M_MMAP_THRESHOLD(数据段和匿名内存映射的临界值)
    • M_MXFAST
    • M_TOP_PAD
      程序必须在调用malloc( )或是其它内存分配函数前使用mallopt( ):
/* use mmap( ) for all allocations over 64KB */
ret = mallopt(M_MMAP_THRESHOLD, 64 * 1024);
if (!ret)
    fprintf(stderr, "mallopt failed! \n");
  1. malloc_usable_size( ):
    用于查询一块已分配内存中有多少可用内存:
#include <malloc.h>
size_t malloc_usable_size(void *ptr);
size_t len = 21;
size_t size;
char *buf;
buf = malloc(len);
if (!buf) {
    perror("malloc");
    return -1;
}
size = malloc_usable_size(buf);
/* we can actually use 'size' bytes of 'buf' ... */

则我们可用过malloc_usable_size( )这个函数得到ptr指向的内存中实际可用大小。

  1. malloc_trim( ):
    该函数允许程序强制glibc归还所有的可释放的动态内存给内核:
#include <malloc.h>
int malloc_trim(size_t padding);
上一篇下一篇

猜你喜欢

热点阅读