Этот код:
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)
Почему еще не удалены? Как удалить общую память? Я запускаю apache в Windows 7.
SHM не доступен изначально в Windows, поэтому PHP пытается эмулировать его в своем «поточно-безопасном диспетчере ресурсов» (TSRM), используя внутренние файлы Windows File Mappings, что является уродливым взломом (/TSRM/tsrm_win32.c).
Поэтому расширение shmop также использует TSRM для SHM в системах Windows. 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 вы не можете удалить общую память.
Вы можете обвинить его либо в эмуляции SHM в TSRM, которая не является правильно исправленной, либо на расширении shmop для слепого использования.
Вы можете попытаться удалить if
и установить shm_perm.key
на -1 безоговорочно и перекомпилировать PHP. Он может только сломать расширение shmop, расширение sysvshm или, возможно, другие расширения, не распространяемые с PHP.
Не стесняйтесь сообщать об этом в PHP bugtracker по адресу http://bugs.php.net/ и исправлять его кем-то, знакомым с внутренними компонентами PHP.
Тем временем, может быть, http://www.php.net/w32api может помочь – вы могли бы использовать CreateFileMapping и друзей из Win32-API более прямым образом с ним. Тем не менее, я никогда не тестировал его, и в PECL он говорит, что он не поддерживается, поэтому будьте осторожны. Это также, конечно, не переносимо.
Вы также можете попытаться обернуть материал shmop_*
в свою собственную библиотеку и поместить свой собственный удаленный флаг в начале сегмента памяти – TSRM все-таки сделает что-то подобное внутри. Но тогда вы можете столкнуться с связанной ошибкой: я думаю, что я помню, как кто-то сообщал, что он не мог создать сегмент с shmop_open()
который был больше, чем последний сегмент, созданный с использованием того же ключа.