Intereting Posts
Задайте переменную в классе, который будет использоваться для нескольких функций / методов JQUERY, чтобы автоматически заполнить выбранный вход от другого входа выбора PHP Неустранимая ошибка: вызов функции-члена функции find () для не-объекта, однако моя функция работает Возвращаемое значение эхо-функции PHP vs echo внутри функции Кодирование JSON с проблемами PHP с массивом PHP 5.4 Не может определять временные зоны самостоятельно Предотвращение отправки двойной формы с использованием токенов Функция PHP Rename Permission denied mysqli и AJAX соединение с базой данных в php с MS Access на хостинге linux Получение информации из базы данных MYSQL & Codeigniter PHP не отображает ошибки Как отображать сообщение только на домашней странице joomla? Шифрование данных в Cocoa, декодирование в PHP (и наоборот) Будет ли регулярное выражение лучше всего подходит для этой проблемы?

Нужна структура массива в PHP с минимальным использованием памяти

В моем скрипте PHP мне нужно создать массив из целых чисел> 600k. К сожалению, для моего webservers memory_limit установлено значение 32M, поэтому при инициализации массива сценарий прерывается сообщением

Неустранимая ошибка: допустимый размер памяти 33554432 байт исчерпан (попытался выделить 71 байт) в /home/www/myaccount/html/mem_test.php в строке 8

Я знаю, что PHP не сохраняет значения массива как простые целые числа, а скорее как zvalues, которые намного больше, чем простое целочисленное значение (8 байтов на моей 64-битной системе). Я написал небольшой скрипт, чтобы оценить, сколько памяти использует каждая запись в массиве, и получается, что это примерно 128 байт. 128 !!! Мне нужно было бы> 73M только для хранения массива. К сожалению, веб-сервер не находится под моим контролем, поэтому я не могу увеличить memory_limit .

Мой вопрос в том, есть ли в PHP возможность создать массив-подобную структуру, которая использует меньше памяти. Мне не нужна эта структура, чтобы быть ассоциативной (достаточно простого доступа к индексу). Также не требуется динамическое изменение размера – я точно знаю, насколько велика будет массив. Кроме того, все элементы будут одного типа. Также как старый добрый C-массив.


Редактирование: поэтому решение deceze работает готово с 32-битными целыми числами. Но даже если вы используете 64-битную систему, пакет () , похоже, не поддерживает 64-битные целые числа. Чтобы использовать 64-битные целые числа в моем массиве, я применил некоторые манипуляции с битами. Возможно, нижеприведенные фрагменты помогут кому-то:

 function push_back(&$storage, $value) { // split the 64-bit value into two 32-bit chunks, then pass these to pack(). $storage .= pack('ll', ($value>>32), $value); } function get(&$storage, $idx) { // read two 32-bit chunks from $storage and glue them back together. return (current(unpack('l', substr($storage, $idx * 8, 4)))<<32 | current(unpack('l', substr($storage, $idx * 8+4, 4)))); } 

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

 $storage = ''; $storage .= pack('l', 42); // ... // get 10th entry $int = current(unpack('l', substr($storage, 9 * 4, 4))); 

Это может быть осуществимо, если инициализация «массива» может быть выполнена одним махом, и вы просто читаете ее из структуры. Если вам требуется много добавления к строке, это становится крайне неэффективным. Даже это можно сделать с помощью дескриптора ресурса:

 $storage = fopen('php://memory', 'r+'); fwrite($storage, pack('l', 42)); ... 

Это очень эффективно. Затем вы можете прочитать этот буфер обратно в переменную и использовать его как строку, или вы можете продолжить работу с ресурсом и fseek .

PHP Judy Array будет использовать значительно меньше памяти, чем стандартный PHP-массив, и SplFixedArray.

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

Вы можете использовать объект, если это возможно. Они часто используют меньше памяти, чем массивы. Также SplFixedArray – хороший вариант.

Но это действительно зависит от того, что вам нужно сделать. Если вам нужна функция для возврата массива и использования PHP 5.5. Вы можете использовать выход генератора для потоковой передачи массива.

Вы можете попробовать использовать SplFixedArray , он быстрее и занимает меньше памяти (комментарий к доктору говорит ~ 30% меньше). Испытайте здесь и здесь .

Я бы сохранил его в строке с фиксированными смещениями и использовал substr для получения необходимого. Быстрая запись / быстрое чтение, меньшая память, возможно, немного неэлегантная, но отлично работает. До тех пор, пока вы можете позволить себе intval (…) читать, конечно.

600K – это много элементов. Если вы открыты к альтернативным методам, я лично буду использовать для этого базу данных. Затем используйте стандартный синтаксис sql / nosql select, чтобы вытащить все. Возможно, memcache или redis, если у вас есть простой хост для этого, например garantiadata.com. Возможно, APC.

В зависимости от того, как вы генерируете целые числа, вы можете потенциально использовать генераторы PHP , предполагая, что вы проходите массив и делаете что-то с отдельными значениями.

Я взял ответ @deceze и завернул его в класс, который может обрабатывать 32-битные целые числа. Это только append-only, но вы все равно можете использовать его как простой, оптимизированный для памяти массив PHP, Queue или Heap. AppendItem и ItemAt – это O (1), и у него нет издержек памяти. Я добавил currentPosition / currentSize, чтобы избежать ненужных вызовов функции fseek. Если вам нужно ограничить использование памяти и автоматически переключиться на временный файл, вместо этого используйте php: // temp .

 class MemoryOptimizedArray { private $_storage; private $_currentPosition; private $_currentSize; const BYTES_PER_ENTRY = 4; function __construct() { $this->_storage = fopen('php://memory', 'rw+'); $this->_currentPosition = 0; $this->_currentSize = 0; } function __destruct() { fclose($this->_storage); } function AppendItem($value) { if($this->_currentPosition != $this->_currentSize) { fseek($this->_storage, SEEK_END); } fwrite($this->_storage, pack('l', $value)); $this->_currentSize += self::BYTES_PER_ENTRY; $this->_currentPosition = $this->_currentSize; } function ItemAt($index) { $itemPosition = $index * self::BYTES_PER_ENTRY; if($this->_currentPosition != $itemPosition) { fseek($this->_storage, $itemPosition); } $binaryData = fread($this->_storage, self::BYTES_PER_ENTRY); $this->_currentPosition = $itemPosition + self::BYTES_PER_ENTRY; $unpackedElements = unpack('l', $binaryData); return $unpackedElements[1]; } } $arr = new MemoryOptimizedArray(); for($i = 0; $i < 3; $i++) { $v = rand(-2000000000,2000000000); $arr->AddToEnd($v); print("added $v\n"); } for($i = 0; $i < 3; $i++) { print($arr->ItemAt($i)."\n"); } for($i = 2; $i >=0; $i--) { print($arr->ItemAt($i)."\n"); }