概要说明
在开始之前,我们需要注意几点:
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);
}
?>
微信扫码添加微信好友