[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: утечка памяти
Tentaclius
Здравствуйте.

Не уверен, что тема относится именно к ветви ООП, но, извините, ничего точнее не подобрал.

Столкнулся с такой проблемой.
Суть скрипта загрузка и анализ некоторых страниц.
Данные загружаются посредством CURL и загоняются в DOMDocument::loadHTML для анализа.
Страниц обрабатывается достаточно много и они не маленькие, но в пределенный момент загруженные страницы по объему занимаемой памяти уж никак не должны превышать лимита сервера в 16МБ. Но тем не менее, превышают. После работы скрипта в течение непродолжительного времени (после обработки страниц 20) скрипт вылетает с сообщением о превышении лимита памяти.

Изначально чтение страниц осуществлялось просто в цикле. Пологая, что проблема в том, что некоторые переменные могут не очищаться автоматически из за одной области видимости, я разнес все части, загружающие новые данные, в различные функции. Результат абсолютно тот же. Не помогло также и unset($xml) по окончанию каждой отдельной обработки.

Вот так выглядит функция загрузки страницы:
PHP
function get_dom($address) {
    
$xml = new DOMDocument();

    if(
READ_METHOD=='http_get') {
        
$par = array( 'timeout' => READ_TIMEOUT );
        if(
USE_PROXY) {
            if(
PROXY_HOST$par['proxyhost'] = PROXY_HOST;
            if(
PROXY_PORT$par['proxyport'] = PROXY_PORT;
        }
        
$txt http_get($address$par);
        
$txt substr($txtstripos($txt"<html>"));
        @
$xml->loadHTML($txt);
    }
    elseif(
READ_METHOD=='curl') {
        
// curl init
        
$ch curl_init($address);
        
curl_setopt($chCURLOPT_RETURNTRANSFERTRUE);
        
// configure
        
if(USE_PROXY) {
            if(
PROXY_HOSTcurl_setopt($chCURLOPT_PROXYPROXY_HOST);
            if(
PROXY_PORTcurl_setopt($chCURLOPT_PROXYPORTPROXY_PORT);
        }
        if(
READ_TIMEOUTcurl_setopt($chCURLOPT_TIMEOUTREAD_TIMEOUT);
        
// process
        
$txt curl_exec($ch);
        
$txt str_replace('&nbsp;'' '$txt);
        
curl_close($ch);
        
// finalize
        
if(!$txt) { echo "cURL: Read error\n"; return false; }
        @
$xml->loadHTML($txt);
        unset(
$txt);
    }
    else {
        @
$xml->loadHTML(get_page($address));
    }
    return 
$xml;
}


Еще используются такие функции для разбора XML по шаблонам (может утечка где-нибудь тут)

PHP
//! ищет дочерний DOM-элемент по тэгу, значению, тексту, аттрибутам
/*!
    Аттрибуты $tagName, $tagValue, $innerText - представлены регулярными выражениями стиля PERL в ограничителях #...#.
    \param $domElement элемент типа DOMElement - узловой элемент, среди дочерних объектов которого ведется поиск.
    \param $tagName элемент типа string - название тэга; если $tag=false, то фильтрация по имени тэга не производится
    \param $tagValue возможное значение тэга (аттрибут value); может быть false.
    \param $innerText текст, входящий в текстовое представление элемента
    \param $attributes ассоциативный массив аттрибутов, по которым ведется фильтрация; значения выражены perl-regexp в regex-скобках |...|
    \return php-массив элементов типа DOMElement
*/
function dom_filter($domElement$tagName$tagValue$innerText$attributes) {
    
$result = array();

    
$elements $domElement->childNodes;

    for(
$i=0$i<$elements->length$i++) {
        
$el $elements->item($i);
        
$valid true;

        
// проверка имени, значения и текстового содержания тэга
        
if($tagName and !preg_opt($tagName$el->nodeName)) $valid=false;
        if(
$tagValue and !preg_opt($tagValue$el->nodeValue)) $valid=false;
        if(
$innerText and !preg_opt($innerText$el->textContent)) $valid=false;

        
// проверка аттрибутов
        
if(is_array($attributes)) {
            
reset($attributes);
            while(
$valid and list($attr_name$attr_value) = each($attributes)) {
                if(!
preg_opt($attr_value$el->getAttribute($attr_name))) {
                    
$valid false;
                    break;
                }
            }
        }

        
// если элемент удовлетворяет условиям, то добавить его в массив, если нет - искать в его дочерних элементах
        
if($valid) {
            
$result []= $el;
        } elseif(
$el->hasChildNodes()) {
            
$subresult dom_filter($el$tagName$tagValue$innerText$attributes);
            
$result array_merge($result$subresult);
        }
    }
    return 
$result;
}

//! Поиск элемента согласно заданному иерархическому шаблону.
//! Функция рекурсивна; использует dom_filter(...) для начальной выборки.\n
/*!
    Пример шаблона: \n
    <code><pre>
    $pattern = array(
        'tag' => '=div',                    // корневой тег
        'value' => '~value',                // значение
        'text' => '~inner_text_pattern',            // шаблон текста, содержащегося в текстовом представлении тэга
        'attr' => array(                // различные свойства тэга
            'class' => '=auto',
            'href' => '~adsfsadf',
            'sel' => true                // вносить этот элемент в таблицу результатов
        ),
        'sub' => array(                    // дочерние тэги
            array(
                'tag' => '=a',
                'text' => '!...',
                'attr' => array('href' => '~/auto.ru/adv/.*'),
                'optional' => true
            ),
            array(
                'tag' => '=img',
                'attr' => array('src' => '=...'),
                'sel' => true
            )
        )
    );
    </pre></code>

    <TABLE><CAPTION>Значимые элементы шаблона</CAPTION>
    <TR><TD> tag <TD> имя тэга
    <TR><TD> value <TD> значение тэга
    <TR><TD> text <TD> текстовое представление
    <TR><TD> attr <TD> массив шаблонов аттрибутов тэга
    <TR><TD> sel <TD> булево значение, будет ли элемент, соответствующий шаблону внесен в итоговый массив
    <TR><TD> optional <TD> обязательно ли наличие элемента в шаблоне (если optional=true, значит необязательно)
    <TR><TD> sub <TD> массив вложенных шаблонов такого же формата
    </TABLE>

    <TABLE><CAPTION>отношения</CAPTION>
    <TR><TD>=<TD>равенство строке
    <TR><TD>-<TD>неравенство строке
    <TR><TD>~<TD>удовлетворение регулярному выражению в стиле PERL в ограничителях #...# (вхождения '#' в текст автоматически заменяется)
    <TR><TD>*<TD>удовлетворение регулярному выражению вне зависимости от регистра
    <TR><TD>!<TD>не удовлетворение регулярному выражению PERL
    <TR><TD>^<TD>не удовлетворение регулярному выражению вне зависимости от регистра
    </TABLE>

    \param $element элемент DOMElement, в котором производится поиск
    \param $pat шаблон фильтрации.
    \return php-массив объектов типа DOMElement, удовлетворяющих шаблону
*/
function dom_struct($element$pat) {
    
$result = array();

    
// первичный отбор элементов
    
$elements dom_filter($element$pat['tag'], $pat['value'], $pat['text'], $pat['attr']);

    
// если результат поиска пуст
    
if(!is_array($elements) or count($elements)==0) {
        return 
$result;
    }
    
// если нет вложенного поиска, то закончить и вернуть найденное
    
if(!is_array($pat['sub']) or count($pat['sub'])==0) {
        if(
$pat['sel']) return $elements;
        else return array(
true);
    }

    
// перебор найденных элементов для рекурсивного поиска
    
for(reset($elements); $el=current($elements); next($elements)) {
        
$tempres = array(); // временный результат, который будет отброшен, если не будет найден хотя бы один вложенный шаблон
        
$valid true;
        
// проверка вложенных шаблонов
        
for($j=0$j<count($pat['sub']); $j++) {
            
$r dom_struct($el$pat['sub'][$j]);
            if(
is_array($r) and count($r)>0) {
                if(
$pat['sel']) $tempres []= $el;
                if(!(
$r[0] === true)) $tempres array_merge($tempres$r);
            } elseif(!
$pat['optional']) {
                
$valid false;
                break;
            }
        }
        if(
$valid$result array_merge($result$tempres);
    }
    return 
$result;
}


Спасибо заранее...



Спустя 6 часов, 19 минут, 11 секунд (6.05.2009 - 16:24) Tentaclius написал(а):
Прошу прощения за беспокойство... Разобрался... Проблема оказалась не в этом участке. Так вот странно среагировал PHP (или я просто его недопонял) на большие массивы внутри часто-вызываемой функции.

Спустя 1 месяц, 28 дней, 7 часов, 24 минуты, 6 секунд (4.07.2009 - 23:48) maximvg написал(а):
Ну раз разобрался, то это хорошо. Тогда посоветую воспользоваться первый правилом программиста: "Если код исправно работает то не трогай его, даже если он не идеален"

Спустя 48 минут, 5 секунд (5.07.2009 - 00:36) kirik написал(а):
Цитата (maximvg @ 4.07.2009 - 15:48)
Тогда посоветую воспользоваться первый правилом программиста: "Если код исправно работает то не трогай его, даже если он не идеален"

Это правило убивает прогресс, развитие программиста как программиста smile.gif
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.