仓酷云

标题: 带来一篇CentOS下同享内存应用罕见圈套与剖析 [打印本页]

作者: 活着的死人    时间: 2015-1-14 21:04
标题: 带来一篇CentOS下同享内存应用罕见圈套与剖析
如果您觉得本篇CentOSLinux教程讲得好,请记得点击右边漂浮的分享程序,把好文章分享给你的小伙伴们!所谓同享内存就是使很多个过程可以拜访统一块内存空间,是最快的可用IPC情势。是针对其他通讯机制运转效力较低而设计的。常常与其它通讯机制,如旌旗灯号量联合应用,来到达过程间的同步及互斥。其他过程能把统一段同享内存段“衔接到”他们本身的地址空间里去。一切过程都能拜访同享内存中的地址。假如一个过程向这段同享内存写了数据,所做的修改会即时被有拜访统一段同享内存的其他过程看到。同享内存的应用年夜年夜下降了在年夜范围数据处置过程当中内存的消费,然则同享内存的应用中有许多的圈套,一不留意就很轻易招致法式瓦解。
跨越同享内存的巨细限制?
在一个linux办事器上,同享内存的整体巨细是无限制的,这个巨细经由过程SHMMAX参数来界说(以字节为单元),您可以经由过程履行以下敕令来肯定SHMMAX的值:
  1. #cat/proc/sys/kernel/shmmax
复制代码
假如机械上创立的同享内存的总共巨细超越了这个限制,在法式中应用尺度毛病perror能够会涌现以下的信息:
  1. unabletoattachtosharedmemory
复制代码
处理办法:
1、设置SHMMAX
SHMMAX的默许值是32MB。普通应用以下办法之一种将SHMMAX参数设为2GB:
经由过程直接更改/proc文件体系,你不需从新启念头器就能够转变SHMMAX的默许设置。我应用的办法是将以下敕令放入/>etc/rc.local启动文件中:
  1. #echo"2147483648">/proc/sys/kernel/shmmax
复制代码
您还可使用sysctl敕令来更改SHMMAX的值:
  1. #sysctl-wkernel.shmmax=2147483648
复制代码
最初,经由过程将该内核参数拔出到/etc/sysctl.conf启动文件中,您可使这类更改永远有用:
  1. #echo"kernel.shmmax=2147483648">>/etc/sysctl.conf
复制代码
2、设置SHMMNI
我们如今来看SHMMNI参数。这个内核参数用于设置体系规模内同享内存段的最年夜数目。该参数的默许值是4096。这一数值曾经足够,平日不须要更改。
您可以经由过程履行以下敕令来肯定SHMMNI的值:
  1. #cat/proc/sys/kernel/shmmni4096
复制代码
3、设置SHMALL
最初,我们来看SHMALL同享内存内核参数。该参数掌握着体系一次可使用的同享内存总量(以页为单元)。简言之,该参数的值一直应当至多为:
  1. ceil(SHMMAX/PAGE_SIZE)
复制代码
SHMALL的默许巨细为2097152,可使用以下敕令停止查询:
  1. #cat/proc/sys/kernel/shmall2097152
复制代码
SHMALL的默许设置关于我们来讲应当足够应用。
留意:在i386平台上RedHatLinux的页面巨细为4096字节。然则,您可使用bigpages,它支撑设置装备摆设更年夜的内存页面尺寸。
屡次停止shmat会涌现甚么成绩?
当初次创立同享内存段时,它其实不能被任何过程所拜访。为了使同享内存区可以被拜访,则必需经由过程shmat函数将其附加(attach)到本身的过程空间中,如许过程就与同享内存树立了衔接。该函数声明在linux/shm.h中:
  1. #include#includevoid*shmat(intshmid,constvoid*shmaddr,intshmflg);
复制代码
参数shmid是shmget()的前往值,是个标识符;
参数shmflg是存取权限标记;假如为0,则不设置任何限制权限。在中界说了几个权限:
  1. #defineSHM_RDONLY010000/*attachread-onlyelseread-write*/#defineSHM_RND020000/*roundattachaddresstoSHMLBA*/#defineSHM_REMAP040000/*take-overregiononattach*/
复制代码
假如指定SHM_RDONLY,那末同享内存区只要读取权限。
参数shmaddr是同享内存的附加点,分歧的取值有分歧的寄义:
?假如为空,则由内核选择一个余暇的内存区;假如非空,前往地址取决于挪用者能否给shmflg参数指定SHM_RND值,假如没有指定,则同享内存区附加到由shmaddr指定的地址;不然附加地址为shmaddr向下舍入一个同享内存低端界限地址后的地址(SHMLBA,一个常址)。
Ø平日将参数shmaddr设置为NULL。
shmat()挪用胜利后前往一个指向同享内存区的指针,应用该指针就能够拜访同享内存区了,假如掉败则前往-1。
其映照关系以下图所示:



.1同享内存映照图

个中,shmaddr表现的是物理内存空间映照到过程的虚拟内存空间时刻,虚拟内存空间中该块内存的肇端地址,在应用中,由于我们普通不清晰过程中哪些地址没有被占用,所以欠好指定物理空间的内存要映照到本过程的虚拟内存地址,普通会让内核本身指定:
  1. unabletoattachtosharedmemory0
复制代码
如许挂载一个同享内存假如是一次挪用是没有成绩的,然则一个过程是可以对统一个同享内存屡次shmat停止挂载的,物理内存是指向统一块,假如shmaddr为NULL,则每次前往的线性地址空间都分歧。并且指向这块同享内存的援用计数会增长。也就是过程多块线性空间会指向统一块物理地址。如许,假如之前挂载过这块同享内存的过程的线性地址没有被shmdt失落,即请求的线性地址都没有释放,就会一向消费过程的虚拟内存空间,很有能够会最初招致过程线性空间被应用完而招致下次shmat或许其他操作掉败。
处理办法:
可以经由过程断定须要请求的同享内存指针能否为空来标识能否是第一次挂载同享内存,若是则应用停止挂载,若不是则加入。
  1. unabletoattachtosharedmemory1
复制代码
附:
函数shmat将标识号为shmid同享内存映照到挪用过程的地址空间中,映照的地址由参数shmaddr和shmflg配合肯定,其原则为:
(1)假如参数shmaddr取值为NULL,体系将主动肯定同享内存链接到过程空间的首地址。
(2)假如参数shmaddr取值不为NULL且参数shmflg没有指定SHM_RND标记,体系将应用地址shmaddr链接同享内存。
(3)假如参数shmaddr取值不为NULL且参数shmflg指定了SHM_RND标记位,体系将地址shmaddr对齐后链接同享内存。个中选项SHM_RND的意思是取整对齐,常数SHMLBA代表了低界限地址的倍数,公式“shmaddrC(shmaddr%SHMLBA)”的意思是将地址shmaddr挪动到低界限地址的整数倍上。
Shmget创立同享内存,当key雷同时,甚么情形下会失足?
shmget()用来创立一个同享内存区,或许拜访一个已存在的同享内存区。该函数界说在头文件linux/shm.h中,原型以下:
  1. unabletoattachtosharedmemory2
复制代码
参数key是由ftok()获得的键值;
参数size是以字节为单元指定内存的巨细;
参数shmflg是操作标记位,它的一些宏界说以下:
IPC_CREATE:挪用shmget时,体系将此值与其他同享内存区的key停止比拟,假如存在雷同的key,解释同享内存区已存在,此时前往该同享内存区的标识符,不然新建一个同享内存区并前往其标识符。
IPC_EXCL:该宏必需和IPC_CREATE一路应用,不然没意义。当shmflg取IPC_CREATE|IPC_EXCL时,表现假如发明内存区曾经存在则前往-1,毛病代码为EEXIST。
留意,当创立一个新的同享内存区时,size的值必需年夜于0;假如是拜访一个曾经存在的内存同享区,则置size为0。
普通我们创立同享内存的时刻会在一个过程中应用shmget来创立同享内存,
  1. unabletoattachtosharedmemory3
复制代码
而在别的的过程中,应用shmget和异样的key来获得到这个曾经创立了的同享内存,
  1. unabletoattachtosharedmemory3
复制代码
假如创立过程和挂接过程key雷同,而对应的size巨细分歧,能否会shmget掉败?
Ø曾经创立的同享内存的巨细是可以调剂的,然则曾经创立的同享内存的巨细只能调小,不克不及调年夜
如:
  1. unabletoattachtosharedmemory5
复制代码
创立了一个4M巨细的同享内存,假如这个同享内存没有删失落,我们再应用
  1. unabletoattachtosharedmemory6
复制代码
来创立一个10M巨细的同享内存的时刻,应用尺度毛病输入会有以下毛病信息:
  1. unabletoattachtosharedmemory7
复制代码
然则,假如我们应用:
  1. unabletoattachtosharedmemory8
复制代码
来创立一个3M巨细的同享内存的时刻,其实不会输入毛病信息,只是同享内存巨细会被修正为3145728,这也解释,应用同享内存的时刻,是用key来作为同享内存的独一标识的,同享内存的巨细不克不及辨别同享内存。
如许会招致甚么成绩?
当多个过程都能创立同享内存的时刻,假如key涌现雷同的情形,而且一个过程须要创立的同享内存的巨细要比别的一个过程要创立的同享内存小,同享内存年夜的过程先创立同享内存,同享内存小的过程后创立同享内存,小同享内存的过程就会获得到年夜的同享内存过程的同享内存,并修正其同享内存的巨细和内容(留心上面的评论弥补),从而能够招致年夜的同享内存过程瓦解。
处理办法:
办法一:
在一切的同享内存创立的时刻,应用排他性创立,即便用IPC_EXCL标志:
  1. unabletoattachtosharedmemory9
复制代码
在同享内存挂接的时刻,先应用排他性创立断定同享内存能否曾经创立,假如还没创立则停止失足处置,若曾经创立,则挂接:
  1. #echo"2147483648">/proc/sys/kernel/shmmax0
复制代码
办法二:
固然都愿望本身的法式能和其他的法式事后商定一个独一的键值,但现实上并非总能够的成行的,由于本身的法式没法为一块同享内存选择一个键值。是以,在此把key设为IPC_PRIVATE,如许,操作体系将疏忽键,树立一个新的同享内存,指定一个键值,然后前往这块同享内存IPC标识符ID。而将这个新的同享内存的标识符ID告知其他过程可以在树立同享内存后经由过程派生子过程,或写入文件或管道来完成,即这类办法不应用key来创立同享内存,由操作体系来包管独一性。
ftok能否必定会发生独一的key值?
体系树立IPC通信(如新闻队列、同享内存时)必需指定一个ID值。平日情形下,该id值经由过程ftok函数获得。
ftok原型以下:
  1. #echo"2147483648">/proc/sys/kernel/shmmax1
复制代码
pathname就时你指定的文件名,proj_id是子序号。
在普通的UNIX完成中,是将文件的索引节点号掏出,后面加上子序号获得key_t的前往值。如指定文件的索引节点号为65538,换算成16进制为0×010002,而你指定的proj_id值为38,换算成16进制为0×26,则最初的key_t前往值为0×26010002。
查询文件索引节点号的办法是:ls-i
但当删除重建文件后,索引节点号由操作体系依据其时文件体系的应用情形分派,是以与本来分歧,所以获得的索引节点号也分歧。
依据pathname指定的文件(或目次)称号,和proj_id参数指定的数字,ftok函数为IPC对象生成一个独一性的键值。在现实运用中,很轻易发生的一个懂得是,在proj_id雷同的情形下,只需文件(或目次)称号不变,就能够确保ftok前往一直分歧的键值。但是,这个懂得并不是完整准确,有能够给运用开辟埋下很隐晦的圈套。由于ftok的完成存在如许的风险,即在拜访统一同享内存的多个过程前后挪用ftok函数的时光段中,假如pathname指定的文件(或目次)被删除且从新创立,则文件体系会付与这个同名文件(或目次)新的i节点信息,因而这些过程所挪用的ftok固然都能正常前往,但获得的键值却其实不能包管雷同。由此能够酿成的效果是,本来这些过程意图拜访一个雷同的同享内存对象,但是因为它们各自获得的键值分歧,现实长进程指向的同享内存不再分歧;假如这些同享内存都获得创立,则在全部运用运转的过程当中外面上不会报出任何毛病,但是经由过程一个同享内存对象停止数据传输的目标将没法完成。
所以假如要确保key_t值不变,要末确保ftok的文件不被删除,要末不消ftok,指定一个固定的key_t值。
假如存在生成key_t值的文件被删除过,则很有能够本身如今应用的同享内存key_t值会和别的一个过程的key_t值抵触,以下面这类情形:



过程1应用文件1来ftok生成了key10000,过程2应用文件2来ftok生成了key11111,此时假如过程1和过程2都须要下载文件,并将文件的内容更新到同享内存,此时过程1和2都须要先下文件,再删失落之前的同享内存,再应用ftok生成新的key,再用这个key去请求新的同享内存来装载新的成绩,然则能够文件2比拟年夜,下载慢,而文件1比拟小,下载比拟慢,因为文件1和文件2都被修正,此时文件1所占用的文件节点号多是文件2之前所占用的,此时假如下载的文件1的ftok生成的key为11111的话,就会和此时还没有能否11111这个key的过程2的同享内存抵触,招致涌现成绩。
处理办法:
办法一:
在有下载文件操作的法式中,对下载的文件应用ftok获得key的时刻,须要停止抵触防止的办法,如应用独有的方法获得同享内存,假如不胜利,则对key停止加一操作,再停止获得同享内存,一向到不会发生抵触为止。
办法二:
下载文件之前,将之前的文件停止mv一下,先“占”着这个文件节点号,避免其他同享内存请求key的时刻获得到。
别的:
创立过程在告诉其他过程挂接的时刻,建议不应用ftok方法来获得Key,而应用文件或许过程间通讯的方法告诉。
同享内存删除的圈套?
当过程停止应用同享内存区时,要经由过程函数shmdt断开与同享内存区的衔接。该函数声明在sys/shm.h中,其原型以下:
  1. #echo"2147483648">/proc/sys/kernel/shmmax2
复制代码
参数shmaddr是shmat函数的前往值。
过程离开同享内存区后,数据构造shmid_ds中的shm_nattch就会减1。然则同享段内存仍然存在,只要shm_attch为0后,即没有任何过程再应用该同享内存区,同享内存区才在内核中被删除。普通来讲,当一个过程终止时,它所附加的同享内存区都邑主动离开。
我们经由过程:
  1. #echo"2147483648">/proc/sys/kernel/shmmax3
复制代码
来删除曾经存在的同享内存。
第一个参数,shmid,是由shmget所前往的标志符。
第二个参数,cmd,是要履行的举措。他可以有三个值:
敕令描写
第三个参数,buf,是一个指向包括同享内存形式与权限的构造的指针,删除的时刻可以默许为0。
假如同享内存曾经与一切拜访它的过程断开了衔接,则挪用IPC_RMID子敕令后,体系将立刻删除同享内存的标识符,并删除该同享内存区,和一切相干的数据构造;
假如仍有其余过程与该同享内存坚持衔接,则挪用IPC_RMID子敕令后,该同享内存其实不会被立刻从体系中删除,而是被设置为IPC_PRIVATE状况,并被标志为”已被删除”(应用ipcs敕令可以看到dest字段);直到已有衔接全体断开,该同享内存才会终究从体系中消逝。
须要解释的是:一旦经由过程shmctl对同享内存停止了删除操作,则该同享内存将不克不及再接收任何新的衔接,即便它仍然存在于体系中!所以,可以确知,在对同享内存删除以后弗成能再有新的衔接,则履行删除操作是平安的;不然,在删除操作以后如仍有新的衔接产生,则这些衔接都将能够掉败!
Shmdt和shmctl的差别:
Shmdt是将同享内存从过程空间detach出来,使过程中的shmid有效化,弗成以应用。然则保存空间。
而shmctl(sid,IPC_RMID,0)则是删除同享内存,完全弗成用,释放空间。
原文链接:http://www.dcshi.com/?p=79


欢迎大家来到仓酷云论坛!
作者: 小女巫    时间: 2015-1-16 23:42
标题: 带来一篇CentOS下同享内存应用罕见圈套与剖析
Linux最大的特点就是其开源性,这一点是十分难得的,这也是它能够存在到现在的原因之一。
作者: 只想知道    时间: 2015-1-26 10:33
掌握在Linux系统中安装软件,在安装Linux工具盘后大致日常所需的软件都会有,一般网络提供下载的软件都会有安装说明。
作者: 灵魂腐蚀    时间: 2015-2-4 20:38
通过自学老师给的资料和向同学请教,掌握了一些基本的操作,比如挂载优盘,编译程序,在Linux环境下运行,转换目录等等。学了这些基础才能进行下面的模拟OS程序。?
作者: 山那边是海    时间: 2015-2-10 09:22
得到到草率的回答或者根本得不到任何Linux答案。越表现出在寻求帮助前为解决问题付出的努力,你越能得到实质性的帮助。
作者: 金色的骷髅    时间: 2015-3-1 10:48
主流Linux发行版都自带非常详细的文档(包括手册页和FAQ),从系统安装到系统安全,针对不同层次的人的详尽文档,仔细阅读文档后40%问题都可在此解决。
作者: 爱飞    时间: 2015-3-10 19:46
目前全球有超过一百多个Linux发行版本,在国内也能找到十几个常见版本。如何选择请根据你的需求和能力,RedhatLinux和DebianLinux是网络管理员的理想选择。
作者: 莫相离    时间: 2015-3-17 12:52
学习Linux应具备的。[书籍+网络资源]
作者: 深爱那片海    时间: 2015-3-24 17:12
这也正是有别的OS得以存在的原因,每个系统都有其自身的优点。?




欢迎光临 仓酷云 (http://ckuyun.com/) Powered by Discuz! X3.2