4

这段代码:

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。

4

1 回答 1

5

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

因此,shmop 扩展也将 TSRM 用于 Windows 系统上的 SHM。 与命令一起shmop_delete()使用来标记内存段被销毁,但是在仿真中是通过以下方式实现的:shmctl()IPC_RMIDIPC_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 扩展以盲目使用它。

您可以尝试无条件地删除ifand 设置为 -1 并重新编译 PHP。shm_perm.key它只能破坏 shmop 扩展本身、sysvshm 扩展或可能其他未随 PHP 分发的扩展。

随时向http://bugs.php.net/上的 PHP bugtracker 报告该问题,并由更熟悉 PHP 内部结构的人修复。

与此同时,也许http://www.php.net/w32api会有所帮助 - 您可以更直接地使用 Win32-API 中的 CreateFileMapping 和朋友。但是,我从未测试过它,并且在 PECL 中它说它没有被维护,所以要小心。它当然也不是便携式的。

您还可以尝试将这些shmop_*东西包装到您自己的库中,并将您自己的已删除标志放在内存段的开头——毕竟 TSRM 在内部做了类似的事情。但是你可能会遇到一个相关的错误:我想我记得有人报告说他无法创建一个shmop_open()比使用相同密钥创建的最后一个段更大的段。

于 2012-09-23T23:08:49.377 回答