php:删除Windows上的共享内存

时间:2012-09-11 21:20:11

标签: php shared-memory php-extension

此代码:

shmop_delete();
shmop_close();

不会删除共享内存。一个实验:

$shmid = @shmop_open(1234, 'a', 0, 0);
var_dump($shmid);

产量

bool(false)

当然。但

$shmid = shmop_open(5678, 'c', 0644, 10);
...
shmop_delete($shmid);
shmop_close($shmid);
...
$shmid = @shmop_open(5678, 'a', 0, 0);
var_dump($shmid);

产量

int(157)

为什么不删除呢?如何删除共享内存?我在Windows 7上运行apache。

1 个答案:

答案 0 :(得分:5)

SHM在Windows中本身不可用,因此PHP尝试在内部使用Windows文件映射在其“线程安全资源管理器”(TSRM)中模拟它,这是一个丑陋的黑客攻击(/TSRM/tsrm_win32.c)。

因此,shmop扩展也在Windows系统上使用TSRM for SHM。 shmop_delete()使用shmctl()IPC_RMID命令来标记销毁的内存段,但是IPC_RMID在仿真中以下列方式实现:

    switch (cmd) {
            [...]
            case IPC_RMID:
                    if (shm->descriptor->shm_nattch < 1) {
                            shm->descriptor->shm_perm.key = -1;
                    }
                    return 0;

其中shm_nattch是段附加到的进程数(或者至少是TSRM认为的数量)。通过将shm_perm.key设置为-1,shmget()的后续访问将被阻止,直到Windows文件映射被销毁。但是,当从shmop_delete()调用此代码时,始终至少PHP进程本身附加到内存段,因此它实际上什么都不做。只有在您致电shmop_close()

后才会分段

所以你的答案是:在没有修复PHP的情况下,在Windows上,你无法删除共享内存。

您可以将其归咎于TSRM中的SHM仿真,它不是正确的,或者是shmop扩展,用于盲目使用它。

您可以尝试删除if并无条件地将shm_perm.key设置为-1并重新编译PHP。它只能破坏shmop扩展本身,sysvshm扩展或可能不与PHP一起分发的其他扩展。

随意向http://bugs.php.net/的PHP bugtracker报告,并由更熟悉PHP内部的人修复。

与此同时,也许http://www.php.net/w32api可以提供帮助 - 您可以使用CreateFileMapping&amp;来自Win32-API的朋友可以更直接地使用它。但是,我从来没有对它进行过测试,在PECL中它说它没有被维护,所以要小心。它当然也不便携。

您也可以尝试将shmop_*内容包装到您自己的库中,并将自己的deleted-flag放在内存段的开头 - 毕竟TSRM在内部做了类似的事情。但是你可能会遇到一个相关的错误:我想我记得有人报告说他无法创建一个shmop_open()的段,该段大于使用相同键创建的最后一段。