php.de

Zurück   php.de > Webentwicklung > PHP-Fortgeschrittene

PHP-Fortgeschrittene Arbeiten mit PHP ohne Einschränkungen

Antwort
 
LinkBack Themen-Optionen Thema bewerten
Alt 28.11.2011, 11:24  
Erfahrener Benutzer
 
Registriert seit: 28.11.2011
Beiträge: 115
PHP-Kenntnisse:
Fortgeschritten
luzip befindet sich auf einem aufstrebenden Ast
Standard Speicherbedarf cli-Skript

Hallo,

ich hab ein Problem mit dem Speicherverbrauch bei einem Skript, das per Cron ausgeführt wird.
Das Skript erstellt eine Sitemap mit ca. 10T Einträgen.

Wenn das Skript läuft, lass ich mir mit memory_get_peak_usage() den Speicherverbrauch ausgeben. Da kommen gleich zu Beginn Werte um 13631488, was an dem Eigenbau-Framework liegen wird. Das sind ja ungefähr 13MB.

top gibt aber gleichzeitig für den PHP-Prozess dazu einen Wert von 166MB aus.

Weiss jemand, woher dieser Unterschied kommen könnte?
Gibt es noch eine bessere Möglichkeit, sich den echten Speicherbedarf während der Ausführung anzeigen zu lassen?

Das Problem dabei ist, dass der Speicherbedarf irgendwann bei 3GB liegt, womit der RAM voll ist.
Kann man vielleicht irgendwie den maximalen Speicher beschränken, aber ohne dass das Skript dann abgebrochen wird?

Vielen Dank für Antworten.

Viele Grüße,
André
luzip ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 28.11.2011, 11:28  
fab
Erfahrener Benutzer
 
Benutzerbild von fab
 
Registriert seit: 28.07.2010
Beiträge: 2.308
PHP-Kenntnisse:
Fortgeschritten
fab ist ein Lichtblickfab ist ein Lichtblickfab ist ein Lichtblickfab ist ein Lichtblickfab ist ein Lichtblick
Standard

Bei einem CLI-Skript, was mit vielen Daten hantiert, muss man auch in PHP etwas sorgsamer mit seiner Speicherbelegung hantieren. Setzt du nicht mehr benötigte Variablen auf null? Löst du zirkuläre Referenzen auf? Letzteres ist vor allem wichtig wenn du noch mit einer älteren Version als 5.3 arbeitest (da wäre aber ohnhin ein Update fällig)
fab ist offline   Mit Zitat antworten
Alt 28.11.2011, 11:37  
Erfahrener Benutzer
 
Registriert seit: 28.11.2011
Beiträge: 115
PHP-Kenntnisse:
Fortgeschritten
luzip befindet sich auf einem aufstrebenden Ast
Standard

Hallo,

danke für die Antwort.

Die PHP-Version ist 5.3.2. Werden die zirkulären Referenzen da nicht selbst aufgelöst?

Die Funktion sieht so aus:

PHP-Code:
function sitemap(&$config,$url,&$list,&$fh,&$errors) {
    
    
$links = array();
    
    
$arr_in = array('ä','ü','ö','ß','&');
    
$arr_out = array('ä','ü','ö','ß','%26');
    
    
$error_keywords = array('mysql','smarty','notice','error','Ã');
    
$page file_get_contents($url);
    
    
//Seite auf Fehler prüfen
    
if ($page=='') {
        
$errors[md5($url)] = array($url,'empty');
    } else {
        foreach (
$error_keywords as $error_keyword) {
            if (
strpos($page,$error_keyword)!==false) {
                
$errors[md5($url)] = array($url,$error_keyword);
                break;
            }
        }
    }

    
//Seite laden und Links extrahieren
    
$html = new DOMDocument('1.0','utf-8');
    
$html->loadHTML($page);
    
$elems $html->getElementsByTagName('a');
    unset(
$page);
    unset(
$html);
    foreach (
$elems as $elem) {
        
        
$href$elem->getAttribute('href');
        
//Es werden nur Links zu anderen Seiten verfolgt. Keine Bilder
        
if (substr($href,-5)!='.html' && substr($href,-4)!='.php') continue;
        
//URLs mit & sind nicht erlaubt
        
if (strpos($href,'&') || strpos($href,'?')) continue;
        
//Keine https-Links verfolgen
        
if (strpos($href,'https://')!==false) continue;
        
//Keine Ahnung, warum das hier auch nötig ist, eigentlich sind die urls bereits mit utf-8 kodiert
        
$href str_replace($arr_in,$arr_out,$href);
        
//Wenn der Link die gleiche Basis-URL enthält oder relativ ist
        
if (strpos($href,$config['url'])==|| strpos($href,'http://')===false || strpos($href,'https://')===false) {
            
//Relative Links werden zu absoluten umgewandelt
            
if (strstr($href,'http://')===false && strstr($href,'https://')===false)
                
$href $config['url'].$href;
            if (!
in_array($href,$list)) {
                
$list[] = $href;
                
fwrite($fh,'<url>'."\n");
                
fwrite($fh,'<loc>'.$href.'</loc>'."\n");
                
fwrite($fh,'<lastmod>'.date('c').'</lastmod>'."\n");
                
fwrite($fh,'<changefreq>weekly</changefreq>'."\n");
                
fwrite($fh,'<priority>0.5</priority>'."\n");
                
fwrite($fh,'</url>'."\n");
                echo 
count($list)."\t".memory_get_peak_usage(true)."\t".$url."\t".$href." gespeichert\n";
                
sitemap($config,$href,$list,$fh,$errors);
            } else {
                echo 
count($list)."\t".memory_get_peak_usage(true)."\t".$href." bereits vorhanden\n";
            }
        }
    }
    

Ich lösche also zwischendurch immer die String-Variablen mit dem Seiteninhalt und das XML-Objekt dazu.
Die Variablen $list (mit der Liste der gefundenen Links), $fh und $errors werden ja nur als Referenz weitergegeben, die sollten also nicht bei jedem neuen Aufruf zusätzlichen Speicher belegen, oder?

Grüße,
André
luzip ist offline   Mit Zitat antworten
Alt 28.11.2011, 12:19  
fab
Erfahrener Benutzer
 
Benutzerbild von fab
 
Registriert seit: 28.07.2010
Beiträge: 2.308
PHP-Kenntnisse:
Fortgeschritten
fab ist ein Lichtblickfab ist ein Lichtblickfab ist ein Lichtblickfab ist ein Lichtblickfab ist ein Lichtblick
Standard

Zitat:
Zitat von luzip Beitrag anzeigen
Die PHP-Version ist 5.3.2. Werden die zirkulären Referenzen da nicht selbst aufgelöst?
PHP 5.3 kann ganz gut damit umgehen, das würde ich als Problem also erstmal ausschließen.

Zitat:
Die Variablen $list (mit der Liste der gefundenen Links), $fh und $errors werden ja nur als Referenz weitergegeben, die sollten also nicht bei jedem neuen Aufruf zusätzlichen Speicher belegen, oder?
Ja, die sind aber auch dein kleinestes Problem (BTW, $fh als Referenz übergeben ist relativ sinnlos, die Variable enthält ja nur eine Resource ID, die sich nicht ändert)

Zitat:
Ich lösche also zwischendurch immer die String-Variablen mit dem Seiteninhalt und das XML-Objekt dazu.
Das unsetten der DOMDocument Instanz ändert aber nichts daran, dass du die jeweilige Rückgabe von getElementsByTagName noch im Speicher hast. Ich nehme an, die Rekursion geht locker mehrere Ebenen tief und da liegt dein Problem.

Ich würde dir raten, die Funktion anders aufzubauen, denn beim rekursiven Aufruf brauchst du den ganzen Overhead eigentlich gar nicht mehr:
Code:
1. lese URL
2. Suche Links und speichere die href-Attribute in Array
3. Zerstöre alle Instanzen von DOM-Objekten
4. Rekursiver Aufruf über das Link-Array
fab ist offline   Mit Zitat antworten
Alt 28.11.2011, 12:53  
Erfahrener Benutzer
 
Registriert seit: 28.11.2011
Beiträge: 115
PHP-Kenntnisse:
Fortgeschritten
luzip befindet sich auf einem aufstrebenden Ast
Standard

Hallo,

ich hab die Funktion mal so umgestellt:

PHP-Code:
function sitemap(&$config,$url,&$list,&$fh,&$errors) {
    
    
$links = array();
    
    
$arr_in = array('ä','ü','ö','ß','&');
    
$arr_out = array('ä','ü','ö','ß','%26');
    
    
$error_keywords = array('mysql','smarty','notice','error','Ã');
    
$page file_get_contents($url);
    
    
//Seite auf Fehler prüfen
    
if ($page=='') {
        
$errors[md5($url)] = array($url,'empty');
    } else {
        foreach (
$error_keywords as $error_keyword) {
            if (
strpos($page,$error_keyword)!==false) {
                
$errors[md5($url)] = array($url,$error_keyword);
                break;
            }
        }
    }

    
//Seite laden und Links extrahieren
    
$html = new DOMDocument('1.0','utf-8');
    
$html->loadHTML($page);
    
$elems $html->getElementsByTagName('a');
    
$links_to_follow = array();
    foreach (
$elems as $elem) {
        
        
$href$elem->getAttribute('href');

        if (
substr($href,-5)!='.html' && substr($href,-4)!='.php') continue;
        
//URLs mit & sind nicht erlaubt
        
if (strpos($href,'&') || strpos($href,'?')) continue;
        
//Keine https-Links verfolgen
        
if (strpos($href,'https://')!==false) continue;
        
//Keine Ahnung, warum das hier auch nötig ist, eigentlich sind die urls bereits mit utf-8 kodiert
        
$href str_replace($arr_in,$arr_out,$href);
        
//Wenn der Link die gleiche Basis-URL enthält oder relativ ist
        
if (strpos($href,$config['url'])==|| strpos($href,'http://')===false || strpos($href,'https://')===false) {
            
//Relative Links werden zu absoluten umgewandelt
            
if (strstr($href,'http://')===false && strstr($href,'https://')===false)
                
$href $config['url'].$href;
        }
        if (
in_array($href,$list)) continue;
        
        
$links_to_follow[] = $href;
        
    }
    unset(
$page);
    unset(
$html);
    unset(
$elems);
    
    foreach(
$links_to_follow as $href) {
        
        
$list[] = $href;
        
fwrite($fh,'<url>'."\n");
        
fwrite($fh,'<loc>'.$href.'</loc>'."\n");
        
fwrite($fh,'<lastmod>'.date('c').'</lastmod>'."\n");
        
fwrite($fh,'<changefreq>weekly</changefreq>'."\n");
        
fwrite($fh,'<priority>0.5</priority>'."\n");
        
fwrite($fh,'</url>'."\n");
        echo 
count($list)."\t".memory_get_peak_usage(true)."\t".$url."\t".$href." gespeichert\n";
        
sitemap($config,$href,$list,$fh,$errors);

    }
    

Meintest Du das so?

Der Speicherbedarf scheint auch etwas besser geworden zu sein, aber die Differenz zwischen
memory_get_peak_usage und top ist immer noch vorhanden.
PHP selbst sagt 41680896, also etwa 41MB, top meldet zeitgleich 360MB.

Hast Du eine Idee, woher diese Differenz kommen kann?

Vielen Dank.

Grüße,
André

PS:
@$fh: Ich dachte, der Resource-Link wird beim Aufruf einer Funktion auch kopiert. Bei 10T Kopien hätte das ja auch zuviel sein können....

Geändert von luzip (28.11.2011 um 13:01 Uhr).
luzip ist offline   Mit Zitat antworten
Alt 28.11.2011, 13:03  
Erfahrener Benutzer
 
Registriert seit: 28.11.2011
Beiträge: 115
PHP-Kenntnisse:
Fortgeschritten
luzip befindet sich auf einem aufstrebenden Ast
Standard

Ich glaub, ich habs. Es war wohl $elem. Das habe ich nicht unsetted.

Jetzt liegt der Verbrauch bei 54MB/64MB. Die 10MB kommen ja wahrscheinlich von PHP selbst...


Danke für die Hilfe!

Viele Grüße,
André
luzip ist offline   Mit Zitat antworten
Alt 28.11.2011, 13:16  
fab
Erfahrener Benutzer
 
Benutzerbild von fab
 
Registriert seit: 28.07.2010
Beiträge: 2.308
PHP-Kenntnisse:
Fortgeschritten
fab ist ein Lichtblickfab ist ein Lichtblickfab ist ein Lichtblickfab ist ein Lichtblickfab ist ein Lichtblick
Standard

Dass eine Differenz vorhanden ist, ist nicht ungewöhnlich, wie sie in diesem Maße zustandekommt, dazu habe ich ehrlich gesagt auch keine Ahnung, daher habe ich mich auch erstmal nur auf das Skript an sich konzentriert. Da sehe ich jetzt eigentlich keine Probleme mehr.. du könntest mal $v=null anstelle von unset($v) probieren, da habe ich zwar keine Primärquelle zu aber gerüchteweise gibt das den Speicher schneller frei.

Edit: unset($elem) stand doch vorhin auch schon drin oder hab ich mir das eingebildet? Das erklärt es natürlich, dadurch sind noch Referenzen zum gesamten DOM-Baum im Speicher geblieben.
fab ist offline   Mit Zitat antworten
Alt 28.11.2011, 13:36  
Erfahrener Benutzer
 
Registriert seit: 03.08.2010
Beiträge: 1.141
PHP-Kenntnisse:
Anfänger
hausl wird schon bald berühmt werdenhausl wird schon bald berühmt werden
Standard

Kurze Zwischenfrage bitte..

Zitat:
Zitat von luzip Beitrag anzeigen
Die Variablen $list (mit der Liste der gefundenen Links), $fh und $errors werden ja nur als Referenz weitergegeben, ...
Ist es eigentlich performancetech. grundsätzlich besser einer Funktion die Argumentenur als Referenz zu &$arg übergeben, wenn man in der Funktion selbst diese nur lesend verwendet??

Danke!
__________________
Keine Zahl != ein Zeichen das keine Zahl ist
hausl ist gerade online   Mit Zitat antworten
Alt 28.11.2011, 13:39  
fab
Erfahrener Benutzer
 
Benutzerbild von fab
 
Registriert seit: 28.07.2010
Beiträge: 2.308
PHP-Kenntnisse:
Fortgeschritten
fab ist ein Lichtblickfab ist ein Lichtblickfab ist ein Lichtblickfab ist ein Lichtblickfab ist ein Lichtblick
Standard

Nein, im Gegenteil. PHP verfolgt das copy-on-write Prinzip, Variableninhalte werden also erst kopiert wenn sie geändert werden.
PHP-Code:
$a 'laaaaaaaaaaaaaaaaaaanger string';
$b $a// $a und $b sind unterschiedliche Variablen, teilen sich aber den Speicher
$b $b '!'// erst jetzt wird kopiert 
fab ist offline   Mit Zitat antworten
Alt 28.11.2011, 13:49  
Erfahrener Benutzer
 
Registriert seit: 03.08.2010
Beiträge: 1.141
PHP-Kenntnisse:
Anfänger
hausl wird schon bald berühmt werdenhausl wird schon bald berühmt werden
Standard

Gut gemacht PHP . Danke fab!
__________________
Keine Zahl != ein Zeichen das keine Zahl ist
hausl ist gerade online   Mit Zitat antworten
Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Prozessorauslastung fällt während Skript läuft (unter Ubuntu) k3kz PHP-Fortgeschrittene 12 13.05.2011 13:59
Daten von Skript in eine DB übertragen und updaten lassen BradPat Datenbanken 5 13.01.2011 15:34
Kann man mit einem eingebundenem PHP Skript auf den Text einer HTML-Seite zugreifen? HottiWF PHP Tipps 2010 10 18.03.2010 18:20
Skript einbau - Sicherheit Rubio PHP Tipps 2010 4 13.02.2010 19:37
perl skript aus php skript aufrufen axmuellser PHP Tipps 2009 1 16.04.2009 17:59
Skript auf einem anderen Server! aha_01 PHP Tipps 2008 3 05.12.2007 09:02
Startup Skript m_haussner Datenbanken 3 10.10.2007 20:56
.htpasswd (im geschützten Ordner!) per skript ändern! Funky_ PHP Tipps 2006 8 22.07.2006 18:03
ein Skript startet ein zweites... ajo_silent PHP-Fortgeschrittene 8 03.05.2006 13:42
Skript &amp;amp;amp;quot;tarnen&amp;amp;amp;quot;? Off-Topic Diskussionen 17 07.08.2005 19:42
Ein php skript aus einem anderen skript heraus aufrufen PHP Tipps 2005-2 8 06.08.2005 20:23
Javascript - CountUP Skript zählt falsch.. Chr!s HTML, Usability und Barrierefreiheit 0 28.03.2005 14:32
[Erledigt] php skript ruft anderes php skript auf PHP-Fortgeschrittene 7 09.01.2005 23:06
SKRIPT GESUCHT - Werbung auf einer site anzeigen Beitragsarchiv 4 29.08.2004 14:07
[Erledigt] Php skript upload problem! PHP Tipps 2004 2 30.06.2004 00:06

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
memory_get_peak_usage

Alle Zeitangaben in WEZ +2. Es ist jetzt 22:44 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum