Linux Program数据管理
Posted Jiamings
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux Program数据管理相关的知识,希望对你有一定的参考价值。
系列文章:
- 文件操作
- 数据管理
- 进程和信号
- POSIX 线程
- 进程间通信:管道
- 信号量共享内存和消息队列
- 套接字
介绍资源分配的管理方式(动态内存管理),介绍如何对可能被多个用户同时访问的文件进行处理(文件锁定)。
内存管理
简单的内存分配
使用标准C语言函数库中的malloc调用来分配内存:
void *malloc(size_t size);
用来指定待分配内存字节数量的参数size不是一个简单的整型,虽然通常是一个无符号整型。
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函数给它返回一个指向1MB内存空间的指针。首先检查malloc函数被成功调用,然后通过使用其中的部分内存来表明分配的内存确实已经存在。当运行这个程序时,可以看到程序输出Hello World,这表明malloc确实返回了1MB的可用内存。
由于mallo函数返回的是一个 void* 指针,因此需要通过类型转换,将其转换至你需要的 char* 类型。malloc 函数可以保证其返回的内存是地址对齐的,所以它可以被转换为任何类型的指针。
分配大量的内存
请求全部的物理内存
int main()
char *some_memory;
size_t size_t_allocate = A_MEGABYTE;
int megs_obtained = 0;
while(megs_obtained < (PHY_MEM_MEGS * 16))
some_memory = (char *)malloc(size_t_allocate);
if(some_memory != NULL)
megs_obtained++;
sprintf(some_memory, "Hello World");
printf("%s - now allocated %d Megabytes\\n", some_memory, megs_obtained);
else
exit(EXIT_FAILURE);
exit(EXIT_SUCCESS);
通过循环来不断申请越来越多的内存,直到它已分配了在PHY_MEM_MEGS中定义的物理内存容量的2倍以上。这个程序似乎耗尽了机器上物理内存中的每个字节,但是出乎意料这个程序运行良好。
每次申请1K内存并在获得的每个内存块上写入数据
int main()
char *some_memory;
int size_to_allocate = ONE_K;
int megs_obtained = 0;
int ks_obtained = 0;
while (1)
for(ks_obtained = 0; ks_obtained < 1024; ks_obtained++)
some_memory = (char *)malloc(size_to_allocate);
if(some_memory == NULL)
exit(EXIT_FAILURE);
sprintf(some_memory, "Hello World");
megs_obtained++;
printf("Now allocated %d Megabytes \\n", megs_obtained);
exit(EXIT_FAILURE);
...
Now allocated 4217 Megabytes
Now allocated 4218 Megabytes
Now allocated 4219 Megabytes
...
当分配的内存大小接近机器物理内存容量时,速度明显变慢,而且你能很明显地感觉到硬盘的操作。但这个程序还是分配了大大超过机器物理内存容量的内存,最后,系统为了保护自己的安全运行,终止这个贪婪的程序。
应用程序所分配的内存是由Linux内核管理的。每次请求内存或者尝试读写它已经分配的内存时,便会由Linux内核接管并决定如何处理这些请求。
刚开始时,内核只是通过使用空闲的物理内存来满足应用程序的内存请求,但是当物理内存耗尽时,它便会开始使用交换空间。与Windows不同,Linux的交换空间中没有局部堆、全局堆或可丢弃内存段等需要在代码中操心的内容 —— Linux 内核会为你完成所有的管理工作。
内核会在物理内存和交换空间之间移动数据和程序代码,使得每次读写内存时,数据看起来总像是已存在于物理内存中,而不管你在访问它们之前,它们在哪里。
用更专业的术语来说,Linux 实现了一个“按需换页的虚拟内存系统”。用户程序看到的所有内存全是虚拟的,也就是说,它不真正存在于程序使用的物理地址上。Linux 将所有的内存都以页为单位进行划分,通常一页的大小为 4096 字节。每当程序试图访问内存时,就会发生虚拟内存倒物理内存的转换,转换的具体实现和耗费的时间取决于你所使用的特定硬件情况。当所访问的内存在物理上并不存在时,就会产生一个页面错误并将控制权交给内核。
Linux 内核会对访问的内存地址进行检查,如果这个地址对于程序来说是合法可用的,内核就会确定需要向程序提供哪一个物理内存页面。然后,如果该页面之前从未被写入过,内核就直接分配给它,如果它已经被保存在硬盘的交换空间上,内核就读取包含数据的内存页面到物理内存(可能需要把一个已有页面从内存中移出到硬盘)。接着,在完成虚拟内存地址到物理地址的映射之后,内核允许用户程序继续运行。Linux 应用程序并不需要操心这一过程,因为所有的具体实现都已隐藏在内核中了。
最终,当应用程序耗尽所有的物理内存和交换空间,或者当最大栈长度被超过时,内核将拒绝最后的内存请求,并可能提前终止程序的运行。
滥用内存
先分配一些内存,然后尝试在它之后写些数据。
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);
程序运行结果:Segmentation fault
Linux 内存管理系统能保护系统的其他部分免受这种内存滥用的影响。为了确保一个行为恶劣的程序无法破坏任何其它程序,Linux会终止其运行。
每个Linux系统中运行的程序都只能看到属于自己的内存映像,不同的程序看到的内存映像不同。只有操作系统知道物理内存是如何安排的,它不为用户程序管理内存,同时也为用户程序提供彼此之间的隔离保护。
空指针
访问空指针情况。
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);
/*
jiaming@jiaming-pc:~/Documents/test$ ./a.out
A read from null (null)
Segmentation fault (core dumped)
*/
第一个printf
函数试图打印一个取自空指针的字符串,接着sprintf
函数尝试向一个空指针里写数据。在本例中,Linux 在 GNU C函数库的容忍下,执行了读操作,它只输出一个包含(NULL) 的魔术字符串,但是对写操作,它直接终止了程序。
这次不使用GNU C 函数库,你将会发现从零地址处读数据也是不被允许的。
int main()
char z = *(const char *) 0;
printf("I read from location zero\\n");
/*
jiaming@jiaming-pc:~/Documents/test$ ./a.out
Segmentation fault (core dumped)
*/
这次,直接尝试从零地址处读数据,而且这次和内核之间并没有GNU lib库的存在,于是,程序被终止了。
释放内存
Linux 内存管理系统完全有能力在程序结束时,将申请的内存返还给系统。但是,如果程序不会结束呢?这需要我们根据需要动态地使用内存。
动态使用内存的程序应该总是通过 free 调用,把不同的内存释放给malloc内存管理器。这样做可以将分散的内存块重新整合到一起,并由malloc函数库来管理而非应用程序。
如果一个运行中的进程自己使用并释放内存,则这些自由内存实际上仍然处于被分配给该进程的状态。在幕后,Linux 将程序员使用的内存块作为一个物理页面管理,通常内存中的每个页面为4K字节。但如果一个内存页面未被使用,Linux 内存管理器就可以将其从物理内存置换到交换空间中,从而减轻它对资源使用的影响。如果程序试图访问位于已置换到交换空间中的内存页中的数据,那么Linux会短暂地暂停程序,将内存页从交换空间再次置换到物理内存,然后允许程序继续运行,就像数据一直存在于内存中一样。
void free(void *ptr_to_memory);
调用 free 时使用的指针参数必须是指向由 malloc、calloc 或 realloc 调用所分配的内存。
int main()
char *some_memory;
int exit_code = EXIT_FAILURE;
some_memory = (char *)malloc(ONE_K);
if(some_memory != NULL)
free(some_memory);
printf("Memory allocated and freed again\\n");
exit_code = EXIT_SUCCESS;
exit(exit_code);
一旦调用了free释放了一块内存,它就不再属于这个进程,它将由mallloc函数库负责管理。在对一块内存调用free之后,就不能再进行读写操作了。
其它的内存分配函数 —— calloc、realloc
void *calloc(size_t number_of_elements, size_t element_size);
void *realloc(void *如果自上次事件以来传感器读数没有更改,则如何在未发送传感器读数时计算窗口上的聚合?