HICK 者,乡巴佬也

数据管理1(Beginning Linux Programming 笔记10)

Posted in: Linux 编程 — Hick @ 2009/06/14 13:14:18

本章主要讲 linux 的动态内存管理、文件锁定以及 dbm 数据库.

p289 linux 中最基本的内存操作为 malloc 函数:

#include <stdlib.h>
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 <unistd.h>
#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 <unistd.h>
#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 从交换分区移动到物理内存,然后让进程继续执行。是对程序来说,相关内存块就像是一直在物理内存中一样。

#include <stdlib.h>
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);

回复

Security Image (验证码必须填写)