c语言内存管理函数
1.获取内存分页大小
函数定义:size_t getpagesize(void) 返回一个系统分页大小的数值,单位为字节(byte)。
附加说明:在 Intel x86 上其返回值应为4096bytes
示例代码:
-
#include<stdio.h>
-
#include<unistd.h>
-
//取得内存分页大小
-
int main()
-
{
-
printf("pagesize = %d\n", getpagesize());
-
return 0;
-
}
运行结果:
2.建立内存映射
头文件:#include <unistd.h> #include <sys/mman.h>
定义函数:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offsize);
函数说明:mmap()用来将某个文件内容映射到内存中,对该内存区域的存取即是直接对该文件内容的读写。
错误代码:
- EBADF 参数fd 不是有效的文件描述词。
- EACCES 存取权限有误。如果是MAP_PRIVATE 情况下文件必须可读,使用MAP_SHARED 则要有PROT_WRITE 以及该文件要能写入。
- EINVAL 参数start、length 或offset 有一个不合法。
- EAGAIN 文件被锁住,或是有太多内存被锁住。
- ENOMEM 内存不足。
代码示例:
-
#include<stdio.h>
-
//mmap内存映射函数
-
#include<sys/types.h>
-
#include<sys/stat.h>
-
#include<fcntl.h>
-
#include<unistd.h>
-
#include<sys/mman.h>
-
int main()
-
{
-
int fd;
-
void *start;
-
struct stat sb;
-
fd = open("/etc/passwd", O_RDONLY);//打开文件
-
fstat(fd, &sb);//取得文件大小
-
start = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE,fd, 0);
-
if(start == MAP_FAILED)//判断映射是否成功
-
{
-
return 0;
-
}
-
printf("%s", start);
-
munmap(start, sb.st_size);//接触映射
-
close(fd);
-
return 0;
-
}
这段代码对指定文件进行读操作,运行结果就是输出/etc/passwd文件中的所有内容,调用mmap函数相当于把文件在一段内存中做了一个映像,我们对文件操作,即对这段内存的操作会直接反映到内核空间,同时我们对内核做任何修改也会很快反映到用户空间。所以对于内核空间<——>用户空间得大量的io操作来说,这种内存映射机制是非常高效率的。
下面让我们来看个实验,来证明这种机制的高效性:
来看看我的一个对比程序:
-
#include<stdio.h>
-
#include<fcntl.h>
-
#include<unistd.h>
-
//用于跟mmap映射以后的读速度对比
-
char buf[100000000];
-
int main()
-
{
-
int fd;
-
fd = open("/home/lyz2wtt/TEST/test.txt" ,O_RDONLY);
-
int len = read(fd, buf, sizeof(buf));
-
printf("%s", buf);
-
return 0;
-
}
我试验得过程是让两个文件都读取一个存储了0~10000000-1个数字的test.txt文件,在这个过程中遇到了问题,我发现了使用mmap函数的好处,因为调用read函数需要一个数据缓冲区,这个数据缓冲区的大小不容易确定,假设是汉子或者是字符不知道字符数量的时候,很明显我们就很难确定缓冲区大小了,而mmap函数自动寻找内存,避免了这种问题。
下面,我们来看二者的速度:
mmap运行测时:
read运行测时:
这样看来并没有看出mmap的优势可能是因为数据量太小
让我们具体看一看mmap函数是什么,它相比read有点在哪?
mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。如下图所示:
由上图可以看出,进程的虚拟地址空间,由多个虚拟内存区域构成。虚拟内存区域是进程的虚拟地址空间中的一个同质区间,即具有同样特性的连续地址范围。上图中所示的text数据段(代码段)、初始数据段、BSS数据段、堆、栈和内存映射,都是一个独立的虚拟内存区域。而为内存映射服务的地址空间处在堆栈之间的空余部分。
由上面我们可以知道,文件的读写其实是对磁盘的数据进行读写,而调用mmap省去了系统调用read,write节省了内核资源,所以进行大数据io操作的效率高。