数据管理1(Beginning Linux Programming 笔记10)
本章主要讲 linux 的动态内存管理、文件锁定以及 dbm 数据库.
p289 linux 中最基本的内存操作为 malloc 函数:
void *malloc(size_t size);
#example:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define A_MEGABYTE (1024 * 1024)
int main() {
char *some_memory;
int megabyte = A_MEGABYTE;
int exit_code = EXIT_FAILURE;
some_memory = (char *)malloc(megabyte);
if (some_memory != NULL) {
sprintf(some_memory, "Hello World\n");
printf("%s", some_memory);
exit_code = EXIT_SUCCESS;
}
exit(exit_code);
}
虽然定义 malloc 返回的是 void * 指针,但是可以用 char * 类型变量来保存,注意这主要是因为当前使用的系统大都是 32 位, 32 位指针可以保存到一个 char * 类型中,64 位下不可以。这里把字符串保存到内存(变量是用的 sprintf 函数)。
p291 以每次 1M 的方式申请内存,并在申请到的内存中写入一掉段字符串,不断分配直到达到两倍物理内存的量(作者给出的为 2G),最终成功执行。接下来每次只分配 1k 内存,程序不断分配下去,执行的时间比较长,磁盘的读写的操作也会很明显,在分配到 1526M 以后,提示 Out of memory, Killed process 2365 。
p292 这里内存的管理(读、写)是由 linux 内核负责的,每次内存操作请求,内核会觉得如何响应。一开始进程申请使用内存时,会分配物理内存给进程使用;当物理内存耗尽,就会开始使用交换分区(swap space, 把磁盘当内存用);比如无法再分配内存时,结束申请内存的进程。内核根据算法在物理内存和交换分区之间移动数据,但是程序中调用起来是没有差别的,当时候到交换分区的时候,由于磁盘操作会比较慢,所以会影响到程序和系统性能。
对进程来说,它使用的内存是虚拟的。Linux 把内存以页为单元进行管理,一般来说一页 4k (分配了 1M 内存不一定就使用了这么多内存)。当进程进行内存操作时,先需要做一个虚拟地址-物理地址的映射。
p293 内存滥用 申请内存的时候需要指定大小,接着往申请的内存中写入数据的时候,有可能申请的内存不够用:
#include <stdlib.h>
#define ONE_K (1024)
int main() {
char *some_memory;
char *scan_ptr;
some_memory = (char *)malloc(ONE_K);
if (some_memory == NULL) exit(EXIT_FAILURE);
scan_ptr = some_memory;
while(1) {
*scan_ptr = '\0';
scan_ptr++;
}
exit(EXIT_SUCCESS);
}
上面的程序中,申请了 1k 的内存,但是以一个死循环的方式,不断的往内存中保存一个一个字符。编译都不会出错,执行程序时,会报告: Segmentation fault 。
p294 空指针
linux 系统对内存有一些保护性措施,可以读一个空指针(返回 null),而写空指针时,会出现 Sagmentation fault 的错误:
#include <stdlib.h>
#include <stdio.h>
int main() {
char *some_memory = (char *)0;
printf("A read from null %s\n", some_memory);
sprintf(some_memory, "A write to null\n");
exit(EXIT_SUCCESS);
}
p295 释放内存
虽然当一个进程结束时,其申请使用的内存会被系统自动释放,但是很多场景下,我们需要主动的释放内存: 使用 free 函数。当一个进程的内存 page 被释放,不再使用时,linux 的内存管理器会把它从物理内存移动到交换分区。如果一个进程尝试操作被移到交换分区的内存 page 的数据,系统会先挂起进程,然后把相关 page 从交换分区移动到物理内存,然后让进程继续执行。是对程序来说,相关内存块就像是一直在物理内存中一样。
void free(void *ptr_to memory);
free 函数只能释放 malloc, calloc, realloc 申请的内存。
p297 其他内存分配函数: calloc()函数有两个参数,分别为元素的数目和每个元素的大小,这两个参数的乘积就是要分配的内存空间的大小,如果调用成功,返回所分配的内存空间的首地址。且会将所分配的内存空间中的每一位都初始化为零,也就是说,如果你是为字符类型或整数类型的元素分配内存,那麽这些元素将保证会被初始化为0;如果你是为指 针类型的元素分配内存,那麽这些元素通常会被初始化为空指针;如果你为实型数据分配内存,则这些元素会被初始化为浮点型的零。calloc()函数是malloc的简单包装。它的主要优点是把动态分配的内存清零。用经验的程序员更喜欢使用calloc(),因为这样的话新分配内存的内容就不会有什么问题,调用calloc()肯定会清0,并且可以避免调用memset().(部分摘自网文)
realloc 函数用于改变分配已申请的内存的大小: void *realloc(void *existing_memory, size_t new_size);

回复