Оптимизация памяти в массиве PHP

Я работаю с большим массивом, который представляет собой карту высот, 1024×1024 и, конечно же, я придерживаюсь предела памяти. В моей тестовой машине я могу увеличить лимит памяти до 1 гб, если захочу, но в моем крошечном VPS с 256 барабанами это не вариант.

Я искал в стеке и google и нашел несколько «ну, вы используете PHP не потому, что эффективность памяти, это и переписывать в c ++», и, честно говоря, это нормально, и я признаю, что PHP любит память.

Но, копаясь больше в управлении памятью PHP, я не нашел, какая память потребляет каждый тип данных. Или, если литье в другой тип данных уменьшает потребление памяти.

Единственная техника «оптимизации», которую я обнаружил, заключалась в том, чтобы отключить переменные и массивы, вот и все.

Преобразование кода в c ++ с использованием некоторых парсеров PHP решит проблему?

Благодаря!

Если вам нужен реальный индексированный массив, используйте SplFixedArray . Он использует меньше памяти. Кроме того, PHP 5.3 имеет гораздо лучший сборщик мусора.

Кроме этого, ну, PHP будет использовать больше памяти, чем более тщательно написанный эквивалент C / C ++.

Использование памяти для целочисленного массива 1024×1024:

  • Стандартный массив: 218 756 848
  • SplFixedArray: 92,914,208

как измерено memory_get_peak_usage()

 $array = new SplFixedArray(1024 * 1024); // array(); for ($i = 0; $i < 1024 * 1024; ++$i) $array[$i] = 0; echo memory_get_peak_usage(); 

Обратите внимание, что тот же массив в C, использующий 64-битные целые числа, будет 8M.

Как и другие, вы можете упаковать данные в строку. Это медленнее, но гораздо эффективнее. Если использовать 8-битные значения, это очень просто:

 $x = str_repeat(chr(0), 1024*1024); $x[$i] = chr($v & 0xff); // store value $v into $x[$i] $v = ord($x[$i]); // get value $v from $x[$i] 

Здесь память будет всего около 1,5 МБ (т. Е. При рассмотрении всех накладных расходов на PHP с помощью этого целочисленного массива строк).

Для удовольствия я создал простой тест создания 8-битных целых чисел 1024×1024, а затем прокручивал их один раз. Упакованные версии все использовали ArrayAccess чтобы код пользователя выглядел одинаково.

  mem write read array 218M 0.589s 0.176s packed array 32.7M 1.85s 1.13s packed spl array 13.8M 1.91s 1.18s packed string 1.72M 1.11s 1.08s 

В упакованных массивах использовались собственные 64-битные целые числа (только для упаковки 7 байтов, чтобы избежать обработки подписанных данных), а в упакованной строке использовались ord и chr . Очевидно, детали реализации и спецификации компьютеров немного повлияют на вещи, но я ожидаю, что вы получите аналогичные результаты.

Таким образом, в то время как массив был в 6 раз быстрее, он также использовал 125x память как следующую лучшую альтернативу: упакованные строки. Очевидно, что скорость не имеет значения, если у вас заканчивается память. (Когда я использовал упакованные строки напрямую без класса ArrayAccess они были только в 3 раза медленнее, чем собственные массивы.)

Короче говоря, чтобы обобщить, я бы использовал что-то другое, кроме чистого PHP, для обработки этих данных, если скорость вызывает какое-либо беспокойство.

В дополнение к принятому ответу и предложениям в комментариях я хотел бы предложить реализацию массива PHP Judy .

Быстрые тесты показали интересные результаты. Массив с 1 миллионом записей с использованием обычной структуры данных массива PHP занимает ~ 200 МБ. SplFixedArray использует около 90 мегабайт. Джуди использует 8 мегабайт. Компромисс в производительности, Джуди занимает удвоенное время регулярной реализации массива php.