Назад | Перейти на главную страницу

Ошибка сегментации PHP при использовании более 128 МБ

У меня установлен SugarCRM. Это сильно загружает память, и это отдельная проблема. Между тем, любая страница, которая пытается использовать более 128 МБ памяти, приводит к остановке процесса Apache (mod_php) с ошибкой сегментации:

[notice] child pid 6852 exit signal Segmentation fault (11)

Если я установлю ограничение памяти PHP на 128M, то я никогда не получу сигнал 11; Я просто получаю обычную ошибку PHP, сообщающую мне, что он не может выделить больше памяти. Если я установил ограничение памяти PHP более 128 МБ - даже немного - тогда любой процесс, направленный в эту память, вызовет ошибку сегментации и белый экран / разорванное соединение для пользователя.

Я использую PHP 5.3.21 на сервере CentOS 6.2 с репозиторием Atomic. Это производственный сервер, поэтому компиляторы отсутствуют, поэтому перекомпиляция процессов Apache для создания дампов ядра невозможна.

У нас установлен APC 3.1.13, и он нужен для некоторых сайтов. Он (я считаю) отключен для моего сайта SugarCRM.

Я не уверен, какие еще подробности необходимы для диагностики этого? Я надеюсь, что есть несколько очевидных вещей, на которые я смогу взглянуть, если кто-то здесь встречал нечто подобное. Что такого в тех 128M, которые вызывают сбой, если использование памяти превышает его?

Редактировать:

Сюжет сгущается. Этот тестовый сценарий выполняется с 256 МБ, установленным в качестве memory_limit, до тех пор, пока процессу PHP не закончится память на уровне около 256 МБ. Это не вызывает ошибки сегментации; он запускается и изящно завершается:

<?php phpinfo();

$array = array();

while (true) {
    $array[] = str_pad('', 1024*512, '0');
    echo " " . memory_get_usage();
}

Итак, мы подошли к тому, что делает SugarCRM (простое приложение PHP / MySQL), которое вызывает ошибку сегментации, но только тогда, когда memory_limit установлено более 128 МБ и достигнута страница, превышающая этот порог в 128 МБ. Это будет очень сложно сузить. Независимо от того, вызвано ли это одной конкретной строкой PHP-кода или конструкцией в приложении, или является результатом целой последовательности действий, которые происходит в приложении (например, выполнение действий, которые запускают сборщик мусора для начала уборки, или отключение объектов, которые открыты соединения с базой данных или что-то вроде того, что я мог себе представить), чтобы вызвать ошибку PHP, неясно.

Я не удивлюсь, если это окажется проблемой сервера, возможно, с обходным путем программирования.

Изменить 2:

Теперь я могу легко воспроизвести ошибку сегментации:

<?php 
function test1() {
    static $instance = 0;
    $instance += 1;
    echo " $instance ";
    test1();
}
test1();

При подобных действиях можно ожидать ошибки сегмента. Лично я бы надеялся, что PHP будет обрабатывать его немного лучше, но, может быть, это обычный курс для PHP? Пока memory_limit установлен на 128M, кажется, что с этим справляются хорошо. Когда я устанавливаю его на 256M, вместо этого он выдаёт ошибки.

Выполняя пошаговое выполнение приложения, кажется, что оно входит в рекурсивный цикл, так как записывает свои начальные файлы кеша (SugarCRM выполняет много кеширования). Это сложно понять, но я подозреваю, что это вызвано отсутствием обработки ошибок - он записывает файл, а затем просто ожидает, что файл будет там, без проверки результатов fopen (). Мы используем SELinux, и теперь мне интересно, не мешает ли это - точно так же и в других приложениях, где PHP is_writeable () говорит: «Хорошо, вы можете написать здесь файл», но затем, когда это делается, SELinux срабатывает. Ан говорит: "ни за что не пишешь который файл здесь ». SugarCRM проверяет первый вопрос, затем не всегда проверяет, действительно ли он был успешным.

Итак - я полагаю, теперь это можно считать проблемой программирования? На мой взгляд, это все еще проблема, связанная с тем, что сервер и PHP не взаимодействуют друг с другом, но адекватные исправления ошибок в SugarCRM должны решить эту проблему.

Это настолько близко, насколько я понял, и, вероятно, насколько я сейчас собираюсь добраться:

  1. SugarCRM не проверяет ошибки своих команд записи файлов должным образом, поэтому иногда не знает, что файл не был записан.

  2. SugarCRM записывает много файлов кэша, когда создает файлы времени выполнения при первом запуске.

  3. При создании этих файлов кэша некоторые неправильные разрешения привели к тому, что некоторые файлы не были записаны правильно.

  4. Отсутствующие файлы помещают SugarCRM в бесконечный рекурсивный цикл, при этом метод записи в кеш вызывает сам себя рекурсивно.

  5. Если для параметра memory_limit PHP установлено значение больше 128M, вместо сообщения о том, что процессу не хватает памяти, возникает ошибка сегментации. Ниже 128M, и процесс PHP убивается более чисто. Я могу только предположить, что это ошибка PHP или ошибка в плагине (не APC). Откуда взялось значение 128M, я не знаю.

Я исправил это, переустановив SugarCRM, установив для всех файлов и каталогов значение 777, и он заработал. Теперь нужно будет отмотать разрешения, пока я не найду, где он не работает. Будет полезен билет в SugarCRM (Community Edition), как и билет в PHP (хотя я ожидаю, что не смогу предоставить им дамп ядра, который они неизбежно запрашивают, так что это может быть тупиком).

Спасибо всем за ваши предложения. Я очень надеюсь, что это будет полезно другим.

Избавьтесь от APC и замените его одним из его альтернатив eAccelerator или XCache. Это было причиной многих лет таинственных сбоев, подобных этой, в моей производственной среде, и все они исчезли, как только исчезла APC.