Unix/Linux环境C编程入门教程(27) 内存那些事儿

  1. calloc() free() getpagesize() malloc() mmap() munmap()函数介绍

calloc(配置内存空间)

相关函数

malloc,free,realloc,brk

表头文件

#include <stdlib.h>

定义函数

void *calloc(size_t nmemb,size_t size);

函数说明

calloc()用来配置nmemb个相邻的内存单位,每一单位的大小为size,并返回指向第一个元素的指针。这和使用下列的方式效果相同:malloc(nmemb*size);不过,在利用calloc()配置内存时会将内存内容初始化为0。

返回值

若配置成功则返回一指针,失败则返回NULL。

范例

/* 动态配置10个struct test 空间*/
#include<stdlib.h>
struct test
{
int a[10];
char b[20];
}
main()
{
struct test *ptr=calloc(sizeof(struct test),10);
}

   




free(释放原先配置的内存)

相关函数

malloc,calloc,realloc,brk

表头文件

#include<stdlib.h>

定义函数

void free(void *ptr);

函数说明

参数ptr为指向先前由malloc()、calloc()或realloc()所返回的内存指针。调用free()后ptr所指的内存空间便会被收回。假若参数ptr所指的内存空间已被收回或是未知的内存地址,则调用free()可能会有无法预期的情况发生。若参数ptr为NULL,则free()不会有任何作用。

   




getpagesize(取得内存分页大小)

相关函数

sbrk

表头文件

#include<unistd.h>

定义函数

size_t getpagesize(void);

函数说明

返回一分页的大小,单位为字节(byte)。此为系统的分页大小,不一定会和硬件分页大小相同。

返回值

内存分页大小。附加说明在Intel x86 上其返回值应为4096bytes。

范例

#include <unistd.h>
main()
{
printf("page size = %d\n",getpagesize( ) );
}

   




malloc(配置内存空间)

相关函数

calloc,free,realloc,brk

表头文件

#include<stdlib.h>

定义函数

void * malloc(size_t size);

函数说明

malloc()用来配置内存空间,其大小由指定的size决定。

返回值

若配置成功则返回一指针,失败则返回NULL。

范例

void p = malloc(1024); /*配置1k的内存*/

   




相关函数

munmap,open

表头文件

#include <unistd.h>
#include <sys/mman.h>

定义函数

void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);

函数说明

mmap()用来将某个文件内容映射到内存中,对该内存区域的存取即是直接对该文件内容的读写。参数start指向欲对应的内存起始地址,通常设为NULL,代表让系统自动选定地址,对应成功后该地址会返回。参数length代表将文件中多大的部分对应到内存。

参数

prot代表映射区域的保护方式有下列组合
PROT_EXEC 映射区域可被执行
PROT_READ 映射区域可被读取
PROT_WRITE 映射区域可被写入
PROT_NONE 映射区域不能存取

参数

flags会影响映射区域的各种特性
MAP_FIXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。
MAP_SHARED对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。
MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的"写入时复制"(copy on write)对此区域作的任何修改都不会写回原来的文件内容。
MAP_ANONYMOUS建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。
MAP_DENYWRITE只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。
MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。
在调用mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。参数fd为open()返回的文件描述词,代表欲映射到内存的文件。参数offset为文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。

返回值

若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1),错误原因存于errno 中。

错误代码

EBADF 参数fd 不是有效的文件描述词
EACCES 存取权限有误。如果是MAP_PRIVATE 情况下文件必须可读,使用MAP_SHARED则要有PROT_WRITE以及该文件要能写入。
EINVAL 参数start、length 或offset有一个不合法。
EAGAIN 文件被锁住,或是有太多内存被锁住。
ENOMEM 内存不足。





   




munmap(解除内存映射)

相关函数

mmap

表头文件

#include<unistd.h>
#include<sys/mman.h>

定义函数

int munmap(void *start,size_t length);

函数说明

munmap()用来取消参数start所指的映射内存起始地址,参数length则是欲取消的内存大小。当进程结束或利用exec相关函数来执行其他程序时,映射内存会自动解除,但关闭对应的文件描述词时不会解除映射。

返回值

如果解除映射成功则返回0,否则返回-1,错误原因存于errno中错误代码EINVAL

参数

start或length 不合法。

范例

参考mmap()

  1. Linux文件与文件描述符的概念
  • 文件的概念

    大多数资源,Linux都是以文件的方式来访问。

Linux中主要的文件类型分为4种:普通文件、目录文件、链接文件和设备文件

Linux中的文件属性:

-rwx rwx rwx

首先,Linux中文件的拥有者可以把文件的访问属性设成3种不同的访问权限:可读(r)、可写(w)和可执行(x)。

文件又有3种不同的用户级别:文件拥有者(u)、所属的用户组(g)和系统里的其他用户(o)

第一个字符显示文件的类型:

"-"表示普通文件

"d"表示目录文件

"l"表示链接文件

"c"表示字符设备

"b"表示块设备

"p"表示命名管道比如FIFO文件

"f"表示堆栈文件比如LILO文件

第一个字符之后的3个三位字符组:

第一个三位字符组表示文件拥有者(u)对该文件的权限

第二个三位字符组表示文件用户组(g)对该文件的权限

第三个三位字符组表示系统其他用户(o)对该文件的权限

若该用户组对此没有权限,一般显示"-"字符

如图所示:

  • 文件描述符。

文件描述符是个很小的正整数,它是一个索引值,指向内核为每个进程所维护的该进程打开文件的记录表。

  1. 内存映射机制与系统调用

    实际上,内存映射机制并不是完全为了共享内存的目的而设计的,它本身提供了不同于一般普通文件的访问方式,进程可以像访问内存一样对普通文件进程操作.而POSIX或System V共享内存IPC则纯粹是用于共享内存的目的.当然内存映射实现共享内存,也是内存映射的应用之一

    内存映射机制的用途: A、以访问内存的方式读写文件; B、实现共享内存;

     

    mmap()系统调用:
       mmap()系统调用使得进程之间通过映射同一个普通文件而实现共享内存的目的.普通文件被映射到进程的地址空间之后,进程就可以像访问普通内存一样对文件进行访问,不必再调用read()、write()等系统调用操作.

       mmap()系统调用介绍:
       void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset);

       该函数在进程的地址空间与文件对象或共享内存对象之间建立一种映射关系;

       addr  :该参数指定文件应该被映射到进程地址空间的起始地址,一般被指定为一个空指针,此时,程序把选择起始地址的任务留给内核来完成了.这个地址是进程地址空间中需要映射到文件中的内存区域的首地址;也就是说,在进程地址空间中用于文件映射的内存区域的首地址;

       len   :文件被映射到调用进程的地址空间中的字节数,它从被映射文件开头offset个字节处开始算起,取len个字节,把文件中的这len个字节的文件空间映射到进程的地址空间中;

       port  :指定文件被映射到内存中之后的访问权限.可取的值有:PORT_READ(可读)、PORT_WRITE(可写)、PORT_EXEC(可执行)、PORT_NONE(不可访问);
       flags :映射标记;取值如下:MAP_SHARED、MAP_PRIVATE、MAP_FIXED,其中,MAP_SHARED和MAP_PRIVATE必选其一,而MAP_FIXED则不推荐使用;

       fd    :即将被映射到进程地址空间中的文件的描述符.一般由系统调用open()返回;同时,fd可以指定为-1,此时,必须指定flags参数中的MAP_ANON,表明进程的是匿名映射(不涉及具体的文件名,避免了文件的创建及打开,很显然,只能用于具有亲属关系的进程之间的通信).

       offset:从文件开头计算offset个字节处开始映射;也就是,文件中需要被映射的文件内容的起始地址,这个起始地址的计算是以文件开头为参照的;这个参数一般取值为0,表示从文件开头处开始映射;
       返回值:文件最终映射到进程地址空间中的起始地址;进程可直接以该地址为有效的起始地址进行操作;也就是文件中开始映射的起始字节点到进程中对应映射内存区的起始地址点处的一个映射;换句话就是说,在进程地址空间中用于文件映射的内存区域的首地址;

    系统调用mmap()用于共享内存的两种方式:
       A、使用普通文件提供的内存映射/共享内存:适用于任何进程之间;此时,需要使用系统调用open()事先打开或创建一个文件,然后再调用mmap():
          fd = open(filename, flag, mode);
          ......
          ptr = mmap(NULL, len, PORT_READ|PORT_WRITE, MAP_SHARED, fd, 0);
         五、解除内存映射关系:
       当进程间通信结束时,需要解除文件页面空间到进程地址空间之间的映射关系;也就说,进程通信结束时,需要把挂载到进程地址空间上的文件卸载下来;这个任务由系统调用munmap();
       int munmap(void* addr, size_t len);
       该系统调用用于在进程地址空间中结束映射关系;
       addr:是调用mmap()返回的进程地址空间中用于文件映射的内存区域的首地址;
       len :进程地址空间中映射区域的大小,单位:字节;
       当映射关系解除之后,对原来映射地址的访问将导致段错误发生;
       返回值: -1:失败; 0:成功;
    内存映射的同步:
       一般来说,进程在映射空间中对共享内容的修改并不会直接写回到磁盘文件中,可以通过调用msync()来实现磁盘上文件内容与共享内存区中的内容与一致

  2. 小试牛刀

    整体流程就是:

    1. 首先打开一个文件,读取出文件信息
    2. 根据文件长度分配相应长度的堆内存
    3. Mmap函数做内存映射
    4. 从内存映射中开始拷贝内容
    5. 输出函数返回的地址开始的内容
    6. 输出完毕之后关闭内存映射文件
    7. 输出拷贝的文件
    8. 释放内存
    9. 关闭文件描述符

    源代码:

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/mman.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdlib.h>#include <string.h>
    int main()
    {
    int fd;//文件描述符
    char *start = NULL,*flag = NULL;//指针接收文件影射的开始地址
    struct stat st;
    printf("page size = %d\n",getpagesize( ) );
    fd=open("read.log",O_RDONLY); /*打开/etc/passwd*/
    if(fd < -1) //打开失败
    return -1;
    printf("打开成功\n");
    fstat(fd,&st); /*取得文件大小*/
    start =(char *) malloc(st.st_size+1);
    if(start == NULL)
    return -1;
    printf("内存分配成功\n");
    flag=mmap(start,st.st_size,PROT_READ,MAP_PRIVATE,fd,0); /*私有不共享*/
    if(flag == MAP_FAILED && start != flag) /*判断是否映射成功*/
    return -1;
    printf("映射成功\n");printf("%s",flag);
    memcpy(start,flag,st.st_size);
    printf("输出完成\n");
    munmap(start,st.st_size); /*解除映射*/
    printf("解除映射完毕\n");return 0;
    }


  3. 各个平台的运行情况

    首先创建testmem.c

    再创建read.log

    在RHEL7上的运行情况

    在RHEL6上

    在MAC上

     

    在Solaris上

    先进入桌面

    将两个文件都拷贝过来

转载于:https://www.cnblogs.com/niulanshan/p/6174851.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/399215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Fix an “Unapproved Caller” SecurityAgent Message in Mac OS X

上午一进公司就被日本分公司的美女呼叫&#xff0c;说mac硬盘加密经常开机后需要输入硬盘加密密码才可以登录&#xff0c;我想应该是硬盘加密后没有给用户添加许可证&#xff0c;所以每次登录系统都要进行验证。于是远程到用户电脑上后&#xff0c;准备在硬盘加密的设置里添加用…

ue 清理缓存_【PM项目管理系统】PM安装更新客户端、删除UE及清理IE缓存操作手册...

第 1 页 共 9 页 PM 安装更新客户端、删除UE 及清理IE 缓存操作手册1、登录地址⑴登陆地址http://www.doczj.com/doc/45b822bf0c22590103029d30.html⑵安装或更新客户端安装客户端如果之前电脑上没有安装过客户端&#xff0c;需要下载并安装客户端。 打开IE 浏览器&#xff0c;…

这绝对是有史以来最详细的web前端学习路线

定要善用开发者工具。firefox的firebug和Chrome的F12都是很好的选择&#xff0c;用好了这个必会发现他带给你的帮助比看一本书更多。你把firebug摸透了你还担心对DOM理解不够&#xff1f;考虑到未来&#xff0c;html5和css3是必须学习的。看这篇总结的最全学习资料&#xff0c;…

cocos2d 走动椭圆

1.效果图艺术与规划说他想与我合作在全国率先主角光环加&#xff0c;椭圆形走动。cocos2d自带没有&#xff0c;參考网上的写了一个。2.椭圆数学知识有关椭圆的数学知识我已经忘光了。网上找了点资料&#xff1a;a是椭圆的长半轴&#xff0c;b是椭圆的短半轴。o是角度&#xff0…

深度学习中用来训练的train.py 探究学习2.0( 数据预处理)

数据预处理 下列代码为train.py中常见的一些数据处理方法 train_transform transforms.Compose([transforms.Resize((224, 224)),transforms.RandomVerticalFlip(),# 随机旋转&#xff0c;-45度到45度之间随机选transforms.RandomRotation(45),# 从中心开始裁剪transforms.C…

go语言入门(三)

条件语句 go语言的条件语句结构如下&#xff1a; go语言的条件语句和其他语言类似。简单列举下&#xff1a; 1、if 语句&#xff0c;布尔表达式不需要括号 if 布尔表达式 {   /* 在布尔表达式为 true 时执行 */   } 2、if...else语句 if 布尔表达式 { /* 在布尔表达式为 tr…

HDU 1950 Bridging signals

那么一大篇的题目描述还真是吓人。 仔细一读其实就是一个LIS&#xff0c;还无任何变形。 刚刚学会了个二分优化的DP&#xff0c;1A无压力。 1 //#define LOCAL2 #include <iostream>3 #include <cstdio>4 #include <cstring>5 using namespace std;6 7 const…

1.8暂停线程

在java中&#xff0c;使用suspend()方法暂停线程&#xff0c;使用resume()方法恢复线程的执行。 1.8.1suspend与resume的使用&#xff1a; 线程代码&#xff1a; public class Thread1 extends Thread {private long i 0L;public long getI() {return i;}public void setI(lon…

JAVA解析纯真IP地址库

2019独角兽企业重金招聘Python工程师标准>>> 用java实现对纯真IP数据库的查询&#xff0c;首先到网上下载QQwry.da文件&#xff0c;读取代码如下&#xff1a;1.IP记录实体类 package com.guess.tools; /** * 一条IP范围记录&#xff0c;不仅包括国家和区域&#xff…

webstorm 代码提示

1、vue语法提示 设置 – Inspections – HTML – Unknown HTML tags&#xff0c;添加customs v-text     v-html     v-once     v-if     v-show     v-else     v-for     v-on     v-bind     v-model     v-ref     v-el   …

Atitit. 提升软件开发效率and 开发质量---java 实现dsl 4gl 的本质and 精髓 O725

Atitit. 提升软件开发效率and 开发质量---java 实现dsl 4gl 的本质and 精髓 O725 1. DSL主要分为三类&#xff1a;外部DSL、内部DSL&#xff0c;以及语言工作台。 1 2. DSL规则 2 2.1. DSL 整洁的代码 2 2.2. DSL必须以文本代码的形式出现 2 2.3. DSL的语法应该尽可能地接近…

java tcp 监听端口_【TCP/IP】端口未监听,还能访问成功?

作者&#xff1a;Mr林_月生链接&#xff1a;https://www.jianshu.com/p/3ab10c8685b5现象直接上图可以发现&#xff0c;本地没监听50000端口的服务&#xff0c;但是尝试连接本地50000端口时&#xff0c;却能成功建立连接&#xff0c;这种现象叫做「自连接」。我们再通过netstat…

python随机生成定长字符串(转)

原文&#xff1a;http://www.oschina.net/code/snippet_153443_4752 运行结果&#xff1a; 转载于:https://www.cnblogs.com/Jollyxi/p/7992007.html

HDU 2204 Eddy's爱好(容斥原理)

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid2204 解题报告&#xff1a;输入一个n让你求出[1&#xff0c;n]范围内有多少个数可以表示成形如m^k的样子。 不详细说了&#xff0c;自己一开始也忽略了三个素数的乘积的乘方的情况。 1 #include<cstdio>2…

python 物理引擎 摩擦力_参赛作品2-phenom的2D物理引擎

全球图形学领域教育的领先者、自研引擎的倡导者、底层技术研究领域的技术公开者&#xff0c;东汉书院在致力于使得更多人群具备内核级竞争力的道路上&#xff0c;将带给小伙伴们更多的公开技术教学和视频&#xff0c;感谢一路以来有你的支持。我们正在用实际行动来帮助小伙伴们…

vue-cli的webpack模版,相关配置文件dev-server.js与webpack.config.js配置解析

1.下载vue-cli [html] view plaincopy npm install vue-cli -g vue-cli的使用与详细介绍&#xff0c;可以到github上获取https://github.com/vuejs/vue-cli 2.安装webpack项目模版 [html] view plaincopy vue init <template-name> <project-name> 比如&#xff…

zookeeper windows 下安装

2019独角兽企业重金招聘Python工程师标准>>> 前沿&#xff1a;最近公司做的项目用到了dubbo 和 zookeeper 由于 每次测试的时候 我本地的服务就会注册到测试机上&#xff0c;还得每次把测试机的服务停止掉&#xff0c;所以准备在本地搭建一个zookeeper。 安装过程 2…

小白学jquery Mobile《构建跨平台APP:jQuery Mobile移动应用实战》连载四(场景切换)...

作为一款真正有使用价值的应用&#xff0c;首先应该至少有两个页面&#xff0c;通过页面的切换来实现更多的交互。比如手机人人网&#xff0c;打开以后先是进入登录页面&#xff0c;登录后会有新鲜事&#xff0c;然后拉开左边的面板&#xff0c;能看到相册、悄悄话、应用之类的…

Mysql学习总结(12)——21分钟Mysql入门教程

21分钟 MySQL 入门教程 目录 一、MySQL的相关概念介绍二、Windows下MySQL的配置 配置步骤MySQL服务的启动、停止与卸载三、MySQL脚本的基本组成四、MySQL中的数据类型五、使用MySQL数据库 登录到MySQL创建一个数据库选择所要操作的数据库创建数据库表六、操作MySQL数据库 向表中…

java 队列实例_Java 实例 - 队列(Queue)用法

全屏Java 实例 - 队列(Queue)用法队列是一种特殊的线性表&#xff0c;它只允许在表的前端进行删除操作&#xff0c;而在表的后端进行插入操作。LinkedList类实现了Queue接口&#xff0c;因此我们可以把LinkedList当成Queue来用。以下实例演示了队列(Queue)的用法&#xff1a;Ma…