Linux Program数据管理

Posted Jiamings

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux Program数据管理相关的知识,希望对你有一定的参考价值。

系列文章:

  • 文件操作
  • 数据管理
  • 进程和信号
  • POSIX 线程
  • 进程间通信:管道
  • 信号量共享内存和消息队列
  • 套接字

介绍资源分配的管理方式(动态内存管理),介绍如何对可能被多个用户同时访问的文件进行处理(文件锁定)。

内存管理

简单的内存分配

使用标准C语言函数库中的malloc调用来分配内存:

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

用来指定待分配内存字节数量的参数size不是一个简单的整型,虽然通常是一个无符号整型。

#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函数给它返回一个指向1MB内存空间的指针。首先检查malloc函数被成功调用,然后通过使用其中的部分内存来表明分配的内存确实已经存在。当运行这个程序时,可以看到程序输出Hello World,这表明malloc确实返回了1MB的可用内存。

由于mallo函数返回的是一个 void* 指针,因此需要通过类型转换,将其转换至你需要的 char* 类型。malloc 函数可以保证其返回的内存是地址对齐的,所以它可以被转换为任何类型的指针。

分配大量的内存

请求全部的物理内存

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define A_MEGABYTE (1024 * 1024)
#define PHY_MEM_MEGS 1024

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内存并在获得的每个内存块上写入数据

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define ONE_K (1024)

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 应用程序并不需要操心这一过程,因为所有的具体实现都已隐藏在内核中了。

最终,当应用程序耗尽所有的物理内存和交换空间,或者当最大栈长度被超过时,内核将拒绝最后的内存请求,并可能提前终止程序的运行。

滥用内存

先分配一些内存,然后尝试在它之后写些数据。

#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);

程序运行结果:​​Segmentation fault​

Linux 内存管理系统能保护系统的其他部分免受这种内存滥用的影响。为了确保一个行为恶劣的程序无法破坏任何其它程序,Linux会终止其运行。

每个Linux系统中运行的程序都只能看到属于自己的内存映像,不同的程序看到的内存映像不同。只有操作系统知道物理内存是如何安排的,它不为用户程序管理内存,同时也为用户程序提供彼此之间的隔离保护。

空指针

访问空指针情况。

#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);


/*

jiaming@jiaming-pc:~/Documents/test$ ./a.out
A read from null (null)
Segmentation fault (core dumped)
*/

第一个​​printf​​​函数试图打印一个取自空指针的字符串,接着​​sprintf​​函数尝试向一个空指针里写数据。在本例中,Linux 在 GNU C函数库的容忍下,执行了读操作,它只输出一个包含(NULL) 的魔术字符串,但是对写操作,它直接终止了程序。

这次不使用GNU C 函数库,你将会发现从零地址处读数据也是不被允许的。

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

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会短暂地暂停程序,将内存页从交换空间再次置换到物理内存,然后允许程序继续运行,就像数据一直存在于内存中一样。

#include <stdlib.h>

void free(void *ptr_to_memory);

调用 free 时使用的指针参数必须是指向由 malloc、calloc 或 realloc 调用所分配的内存。

#include <stdlib.h>
#include <stdio.h>

#define ONE_K (1024)

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

#include <stdlib.h>

void *calloc(size_t number_of_elements, size_t element_size);
void *realloc(void *如果自上次事件以来传感器读数没有更改,则如何在未发送传感器读数时计算窗口上的聚合?

Linux Program进程间通信:管道

按下按钮时从 STM32 ADC 获取读数

Linux Program套接字

Linux Program信号量共享内存和消息队列

java中默认的安装路径中有空格,其中的空格是指啥,是指program file吗???跪求详解!!!