Как я могу предотвратить утечку памяти в файле импорта CSV / ISBN сценарий поиска - PullRequest
0 голосов
/ 23 сентября 2010

Мой сайт позволяет пользователям загружать CSV-файл со списком книг. Затем скрипт читает этот файл и проверяет номер isbn для Amazon, используя класс PEAR Services_Amazon, возвращая расширенные данные книги. Однако всякий раз, когда я запускаю скрипт в списке книг, объем потребляемой памяти постоянно увеличивается, пока я не получу фатальную ошибку. На данный момент, с выделением 32 МБ, я могу прочитать только 370 записей файла CSV, прежде чем он выйдет из строя.

У меня есть пользователь с файлом записи 4500 для импорта и виртуальный сервер с 256 МБ ОЗУ, поэтому увеличение лимита памяти не является решением.

Вот упрощенная версия импорта CSV:

$handle = fopen($filename, "r");
 while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
 $isbn = $data[6];
 checkIsbn($isbn);
 }

Вот урезанная версия функции:

function checkIsbn($isbn) {     
 $amazon = &new Services_Amazon(ACCESS_KEY_ID, SECRET_KEY, ASSOC_ID);
 // -- $options array filled with $isbn, other requested info --
 $products = $amazon->ItemSearch('Books', $options);        
 // -- Then I create an array from the first result --
  $product = $products['Item'][0];
  $title = $product['ItemAttributes']['Title']; 
  // -- etc... various attributes are pulled from the $product array --
 mysql_query($sql); // -- put attributes into our DB
  unset($product); 
  unset($products);
  usleep(1800000); // maximum of 2000 calls to Amazon per hour as per their API
return $book_id;    
 }

Что я пробовал: сбросить массивы и установить их в NULL, как в функции, так и в коде импорта CSV. Я увеличил все мои тайм-ауты, чтобы убедиться, что это не проблема. Я установил xdebug и провел несколько тестов, но все, что я обнаружил, это то, что скрипт постоянно увеличивал объем памяти при каждом обращении к классу Amazon (я не эксперт по xdebug). Я думаю, что, возможно, переменные в классе Services_Amazon не очищаются каждый раз, когда он запускается, но не знаю, куда идти дальше. Я надеялся, что сброс двух массивов сделает это, но не повезло.

Редактировать: Обновление: я решил, что это может быть проблемой в классе PEAR (и, глядя на некоторые из вопросов, касающихся PEAR, это кажется возможным). В любом случае, мои навыки ООП на данный момент очень малы, поэтому я нашел способ сделать это, перезагрузив страницу несколько раз - подробности см. В моем ответе ниже.

Ответы [ 3 ]

3 голосов
/ 23 сентября 2010

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

также лучше постараться не копировать память, а просто сделать $ produkt и $ title указателем, назначив только ссылки на $ products;

$product = &$products['Item'][0];
$title = &$product['ItemAttributes']['Title']; 

, тогда вместо unset () сделайте

$products = NULL;
unset($products);

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

и почему вы создаете новый экземпляр i-ого Serverces_Amazon каждый раз, когда вызывается функция, которую я вызывал?как насчет члена класса для создания экземпляра при создании объекта.

class myService
{
    protected $_service;

    public function __construct()
    {
        $this->_service = new Services_Amazon(ACCESS_KEY_ID, SECRET_KEY, ASSOC_ID);
    }

    public function checkIsbn($isbn)
    {
        //...
        $this->_service->ItemSearch('Books', $options);
        //...
    }
}

$myService = new myService;
$handle = fopen($filename, "r");
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {

    $bookId = $myService->checkIsbn($data[6]);
}

и, кроме того, вы предполагаете, что все ваши пользователи используют один и тот же формат CSV, что весьма маловероятно ... так что лучше использовать настоящий анализатор CSVкоторый может обрабатывать все возможные обозначения CSV ...

0 голосов
/ 24 сентября 2010

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

0 голосов
/ 23 сентября 2010

Как насчет создания только одного экземпляра объекта $amazon и передачи его в функцию checkIsbn?Они вам не нужно создавать 4500 экземпляров.$amazon = &new Services_Amazon(ACCESS_KEY_ID, SECRET_KEY, ASSOC_ID); $handle = fopen($filename, "r"); while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { $isbn = $data[6]; checkIsbn($amazon, $isbn); } unset($amazon);

...