linux系统编程-内存管理day01

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

内存管理

进程地址空间

linux将它的物理内存虚拟化,进程并不能直接在物理内存上寻址,而是由linux内核为每个进程维护一个特殊的虚拟地址空间(virtual address space)。

页和页面调度

共享和写时复制

允许不同的虚拟地址空间共享(share)物理内存上的数据。共享的数据可能是只读的,或者是可读可写的。(一个物理页可能被分配给不同的进程,即进程共享这个页)
当某个进程试图写某个共享页时可能有两种情况:

  1. 内核允许这个操作
  2. 内存管理单元(MMU)会截取这次写操作并产生一个异常,然后内存会创造一份这个页的拷贝以供该进程进行写操作,这种方法叫写时拷贝(COW, copy-on-write)。读时可以共享读,只有进程在对共享页写时才能获得一份新的拷贝。

存储器区域

内核将具有某些相同特征的页组织成块(blocks),例如读写权限。
每个进程都有以下存储器区域:

动态内存分配

所有内存管理系统的基础都是动态内存的分配,使用以及最终的返回。

C中获取动态内存的接口

1.malloc( ):
得到一个size大小的内存区域,并返回一个指向这部分内存首地址的指针。(其中的内容是未定义的,并非全部是0)

#include <stdlib.h>
void *malloc(size_t size);

malloc的使用:

char *p;
p = malloc(2048);
if (!p)
  perror("malloc");

注:C会自动地把返回值由void指针转变为需要的类型,但是C++需要自己强转:

char *name;
name = (char *) malloc(512);
if (!name)
  perror("malloc");

2.xmalloc( ):
当malloc( )返回NULL时就打印错误和终止程序:

/* like malloc( ), but terminates on failure */
void *xmalloc(size_t size)
{
  void *p;
  p = malloc(size);
  if (!p) {
    perror("xmalloc");
    exit(EXIT_FAILURE);
  }
  return p;
}

3.calloc( ):
用于分配动态数组,

#include <stdlib.h>
void *calloc(size_t nr, size_t size);

调用calloc( )成功时会返回一个指针,指向一块可以存储下整个数组的内存(nr个元素,每个为size个字节).

4.realloc( ):
C语言提供了一个接口来改变(变大或变小)已经得到的动态内存的大小:

#include <stdlib.h>
void *realloc(void *ptr, size_t size);

成功调用realloc( )将ptr指向的内存区域的大小变为size字节。

动态内存的释放

自动内存分配,当栈不在使用,空间被自动释放。而动态内存需要显式地释放。

#include <stdlib.h>
void free(void *ptr);
对齐

数据的对齐(alignment)是指数据地址和由硬件确定的内存块之间的关系。

在大多数情况下, 编译器和C库会自动处理对齐的问题。在Linux中,malloc( )等函数返回的都是(8字节对齐(32位系统), 16字节对齐(64位系统))。
但是对于更大的边界,例如页面,需要动态的对齐。最基本的工作是将直接块I/O或是其它软硬件通信的缓冲区对齐

  1. posix_memalign( )
/* one or the other -- either suffices */
#define _XOPEN_SOURCE 600
#define _GNU_SOURCE
#include <stdlib.h>
int posix_memalign(void **memptr, size_t alignment, size_t size);

调用posix_memalign( ), 成功时会返回size字节的动态内存,并保证是按照alignment进行对齐的。参数alignment必须是2的幂,以及void指针大小的倍数。返回的内存块的地址保存在memptr里,函数返回0。

其他对齐问题

复杂的数据结构的对齐问题将会比标准类型的更复杂。另外,在对不同类型的指针进行赋值以及强制类型转换的时候,对齐的问题也很重要。
非标准类型。非标准和复杂的数据类型的对比比简单的自然对齐有着更多的要求:

使用指针和强转时也可能有对齐错误。例如以下代码:

char greeting[] = "ahoy matey";
char *c = greeting[1];
unsigned long badnews = *(unsigned long  *)c;

当c被强转后再进行读取将会导致对齐错误。小者是性能损失,大者是整个程序崩溃。

上一篇 下一篇

猜你喜欢

热点阅读