概要说明
在开始之前,我们需要注意几点:
1.要了解内存的管理机制;
2.在要使用内存时要先申请;
3.在使用完毕后要及时释放资源;
4.要预防死锁;
5.在产生死锁时,应该有一个可靠,稳定的解决方案;
本函数库提供 System V 的信号处理机制。这个机制可以让系统限制同时使用行程所存取的资源。本函数库亦提供了内存共享的机制,可让不同的程序存取相同的变量,方便交换程序信息。
下表为系统的共享内存的限制值
SHMMAX 共享内存的最大值,一般为 131072 bytes
SHMMIN 共享内存的最小值,一般为 1 byte
SHMMNI 内存共享部分的最大值,一般为 100
SHMSEG 每个行程所能共享的最大内存空间,一般为 6
sem_get: 取得信号代码。
sem_acquire: 捕获信号。
sem_release: 释出信号。
shm_attach: 打开建立共享内存空间。
shm_detach: 中止共享内存空间链接。
shm_remove: 清除内存空间。
shm_put_var: 加入或更新内存空间中的变量。
shm_get_var: 取得内存空间中指定的变量。
shm_remove_var: 删除内存空间中指定的变量。
管理共享内存
server:/home/xisxy$ ipcs -sa
Semaphores:
T ID KEY MODE OWNER GROUP CREATOR CGROUP NSEMS OTIME CTIME
s 65536 5432001 --rw------- _postgresql _postgresql _postgresql _postgresql 17 13:01:18 13:01:18
s 65537 5432002 --rw------- _postgresql _postgresql _postgresql _postgresql 17 13:01:18 13:01:18
s 65538 5432003 --rw------- _postgresql _postgresql _postgresql _postgresql 17 1:30:05 13:01:18
s 262147 0 --rw-rw-rw- www www www www 1 no-entry 0:00:52
s 262148 0 --rw-rw-rw- www www www www 1 no-entry 0:00:52
s 262149 0 --rw-rw-rw- www www www www 1 no-entry 0:00:52
s 1966086 0 --rw-rw-rw- www www www www 1 no-entry 19:18:32
s 1966087 0 --rw-rw-rw- www www www www 1 no-entry 19:18:32
s 1966088 0 --rw-rw-rw- www www www www 1 no-entry 19:18:32
server:/home/xisxy$ ipcrm -s 262147
也可以用如下方式,一次全部清理:
for i in `ipcs |grep www|awk '{print $2}'` do ipcrm -m $i ipcrm -s $i done
共享内存查看清除命令ipcs和ipcrm
ipcs: check the shared memory allocation on a system ipcrm: manually deallocate shared memory on a system
取得ipc信息:
ipcs [-m|-q|-s]
-m 输出有关共享内存(shared memory)的信息
-q 输出有关信息队列(message queue)的信息
-s 输出有关“遮断器”(semaphore)的信息
删除ipc(清除共享内存信息)
ipcrm -m|-q|-s shm_id
查看与修改共享内存配置
Finding out shared memory kernel settings in FreeBSD:
sys1# sysctl -a | grep -i SHM kern.ipc.shmmax: 4194304 kern.ipc.shmmin: 1 kern.ipc.shmmni: 96 kern.ipc.shmseg: 64 kern.ipc.shmall: 1024 kern.ipc.shm_use_phys: 0
以root身份进行修改 /etc/sysctl.conf 这个文件,加入以下的语句:
kernel.shmmax = 2147483648 kernel.shmmni = 4096 kernel.shmall = 2097152 kernel.sem = 250 32000 100 128 fs.file-max = 65536 net.ipv4.ip_local_port_range = 1024 65000
注:
sem 4个参数依次为SEMMSL(每个用户拥有信号量最大数);
SEMMNS(系统信号量最大数);
SEMOPM(每次semopm系统调用操作数);
SEMMNI(系统辛苦量集数最大数)。
Shmmax 最大共享内存2GB
物理内存如果小的话可以设置成 536870912。
Shmmni 最小共享内存 4096KB。
Shmall 所有内存大小
一般情况下可以设置最大共享内存为物理内存的一半,如果物理内存是 2G,则可以设置最大共享内存为 1073741824,如上;如物理内存是 1G,则可以设置最大共享内存为 512 * 1024 * 1024 = 536870912;以此类推。
在redhat上最大共享内存不建议超过 4*1024*1024*1024-1=4294967295
设置完成后用命令 more /etc/sysctl.conf |grep kernel.s 检查
建议重启系统再继续下面的操作。
测试与比较
<?php /* *读写磁盘文件 和 读写内存比价 */ echo '阿里云1核2G Ubuntu(64)<br />'; test_dm(1000); //test_dm(2000); //test_dm(3000); function test_dm($loop = 1) { @unlink('data_out_memory.txt'); @unlink('data_out_disk.txt'); @unlink('data_in.txt'); $test_result = '<br />相同条件下循环'.$loop.'次运算时间'.PHP_EOL.'<br />'; //写磁盘文件 $start = microtime_float(); //$test_result .= '写磁盘文件开始'.$start.PHP_EOL.'<br />'; for($i=1; $i<=$loop; $i++){ $data_in = 'abcdefghijklmnopqrstuvwxyz1234567890'; @file_put_contents('data_in.txt',$data_in,FILE_APPEND); } $end = microtime_float(); //$test_result .= '写磁盘文件结束'.$end.PHP_EOL.'<br />'; $test_result .= '写磁盘耗时:'.($end - $start).PHP_EOL.'<br />'; //读磁盘文件 $start = microtime_float(); //$test_result .= '读磁盘开始'.$start.PHP_EOL.'<br />'; for($i=1; $i<=$loop; $i++){ $data_out .= @file_get_contents('data_disk_read.txt'); } $end = microtime_float(); //$test_result .= '读磁盘结束'.$end.PHP_EOL.'<br />'; $test_result .= '读磁盘耗时:'.($end - $start).PHP_EOL.'<br />'; //转存读取数据 测试完整性 @file_put_contents('data_out_disk.txt',$data_out); //写内存 $start = microtime_float(); //$test_result .= '写内存文件开始'.$start.PHP_EOL.'<br />'; for($i=1; $i<=$loop; $i++){ $data_in = 'abcdefghijklmnopqrstuvwxyz1234567890'; $shmid = shmop_open($i, 'c', 0755, 100); shmop_write($shmid, $data_in, 0); shmop_close($shmid); } $end = microtime_float(); //$test_result .= '写内存文件结束'.$end.PHP_EOL.'<br />'; $test_result .= '写内存耗时:'.($end - $start).PHP_EOL.'<br />'; //读内存 $start = microtime_float(); //$test_result .= '读内存文件开始'.$start.PHP_EOL.'<br />'; for($i=1; $i<=$loop; $i++){ $shmid = shmop_open($i, 'c', 0755, 100); $data_out.= shmop_read($shmid, 0, 32).'\r\n'; shmop_close($shmid); } $end = microtime_float(); //$test_result .= '读内存文件结束'.$end.PHP_EOL.'<br />'; $test_result .= '读内存耗时:'.($end - $start).PHP_EOL.'<br />'; //转存读取数据 测试完整性 @file_put_contents('data_out_memory.txt',$data_out); //DEBUG 输出测试结果 echo $test_result; } function microtime_float() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } ?>
<?php /* * 基于PHP共享内存, 任务消息队列示例 */ $token = create_token(); //DEBUG 进队列 返回内存地址 $systemid = queue_in($token,$queue_length=10); //DEBUG 出队列 注销内存地址 queue_out($token,$systemid); /* *唯一标记token *@return token */ function create_token() { $token = $_SERVER['HTTP_USER_AGENT'].$_SERVER['REMOTE_ADDR'].microtime().rand(); return '#'.sha1($token); } /* * DEBUG 进队列 队列满则返回等待 * @pram $token 用户唯一标记 * @pram $queue_length 队列长度 * @return 0 队列满 等待进队列; 大于 1 表示返回内存地址 */ function queue_in($token,$queue_length=10){ $systemid = 0; // System ID for the shared memory segment $mode = "c"; // Access mode $permissions = 0755; // Permissions for the shared memory segment $size = 100; // Size, in bytes, of the segment for($systemid=1; $systemid <= $queue_length; $systemid++){ $shmid = shmop_open($systemid, $mode, $permissions, $size); $is_empty = shmop_read($shmid, 0, 1); if('#' != $is_empty){ shmop_write($shmid, $token, 0); return $systemid; } shmop_close($shmid); } return 0; } /* * DEBUG 出队列 * @pram $token 用户唯一标记 * @pram $systemid 内存地址 */ function queue_out($token,$systemid=0){ $mode = "c"; // Access mode $permissions = 0755; // Permissions for the shared memory segment $size = 100; // Size, in bytes, of the segment $shmid = shmop_open($systemid, $mode, $permissions, $size); shmop_delete($shmid); shmop_close($shmid); } function microtime_float() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } ?>
微信扫码添加微信好友