Ankündigung

Einklappen
Keine Ankündigung bisher.

Merkwürdiges zur Speichernutzung/Optimierung bei Arrays PHP 7.4

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Merkwürdiges zur Speichernutzung/Optimierung bei Arrays PHP 7.4

    Hallo,
    habe den folgenden Test gemacht:

    PHP-Code:
    <?php
    require __DIR__."/../class/class.debug.php";

    debug::systeminfo()."<br>";
    $test $test2 = [];
    debug::write();
    for (
    $i 0$i 10000$i++) {
        
    $test[] = '97c2ca84-bcfe-4618-b8a3-4d404eead37a0';
        
    //$test[] = '97c2ca84-bcfe-4618-b8a3-4d404eead37a'.$i%1;
    }
    debug::write($test === $test2);  

    debug::write();
    for (
    $i 0$i 10000$i++) {
        
    $test2[] = '97c2ca84-bcfe-4618-b8a3-4d404eead37a'.$i%1;
        
    //$test2[] = '97c2ca84-bcfe-4618-b8a3-4d404eead37a0';
    }
    debug::write($test === $test2);  
    $test $test2 = [];
    debug::write();
    Ausgabe:
    [20.10.2020 19:53:42,968](485k/687k) Debug::write "class.debug.php" Line 393 <="arraymem.php" Line 4 Debug :: systeminfo()
    0 string(24) ASCII "WINNT PHP 7.4.2 (64Bit) "
    [20.10.2020 19:53:42,968][+96 μs](484k/687k) Debug::write "arraymem.php" Line 6
    [20.10.2020 19:53:42,968][+432 μs](1001k/1002k) Debug::write "arraymem.php" Line 11
    0 boolean false
    [20.10.2020 19:53:42,968][+69 μs](1000k/1003k) Debug::write "arraymem.php" Line 13
    [20.10.2020 19:53:42,969][+1194 μs](2142k/2143k) Debug::write "arraymem.php" Line 18
    0 boolean true
    [20.10.2020 19:53:42,969][+119 μs](484k/2144k) Debug::write "arraymem.php" Line 20
    Es wird auf unterschiedliche Weise zwei mal ein Array mit identischen Inhalt erzeugt. Der Beweis das die Arrays test und test2 identisch sind zeigt die Ausgabe Zeile 18 (true).
    Interessant ist der Speicherbedarf (in Klammern akt.Wert/Spitze). Für das Array mit der Zuweisung '97c2ca84-bcfe-4618-b8a3-4d404eead37a0'; steigt der Bedarf von 484k -> 1001k.
    Das Array test2 wird "berechnet". $i%1 ist jedoch immer 0. Dennoch ist der Speicherbedarf bedeutend höher (1000k -> 2142k).

    Meine Vermutung ist, das im Fall vom Array test PHP erkennt das alle Elemente identisch sind und das Array ganz anders speichert.

    Werden die Zuweisungen getauscht (auskommentiert) dreht sich das Verhalten um. Dann benötigt test mehr Speicher als test2. Sozusagen der Beweis das die Reihenfolge der Array-Erzeugung dafür nicht verantwortlich ist.

    Ebenfalls interessant das mit dem Löschen der Arrays der aktuelle Speicherbedarf wieder auf den Startwert geht.

  • #2
    PHP arbeitet intern mit copy on write. Der String wird einmal im Speicher angelegt und alle Array Elemente zeigen intern auf diesen String. Erst wenn du den Inhalt eines Elementes manipulierst, wird dieser im Speicher kopiert.
    Folgndes sollte zum selbsen Speicherverbrauch wie Variante 2 führen: (hinter der ersten Schleife einfügen)
    PHP-Code:
    for ($i 0$i 10000$i++) {
        
    $test[$i] .= '';

    (eventuell ist php auch schlau... dann ggf. mit $test[$i] .= '.'; testen)

    Kommentar


    • #3
      Mit "copy on write" verbinde ich folgenden Effekt:

      PHP-Code:
      $a=[];
      debug::write();  //562k
      $a array_fill(0,10000,"abcdefghij");
      debug::write();  //1078k
      $b $a;
      debug::write();  //1078k
      $b[0] = "abcdefghij";
      debug::write();  //1595k 
      Mit der Zuweisung $b = $a passiert in Bezug auf den Speicher noch nichts. Erst mit $b[0] = "abcdefghij"; wird das erste Element manipuliert und eine komplette Kopie im Speicher erstellt.

      Der Fall oben liegt etwas anders. Das
      Der String wird einmal im Speicher angelegt und alle Array Elemente zeigen intern auf diesen String. Erst wenn du den Inhalt eines Elementes manipulierst, wird dieser im Speicher kopiert.
      trifft es fast. Aber wenn hier ein Element manipuliert wird nicht gleich das ganze Array neu strukturiert, sondern wohl nur die Elemente welche manipuliert werden.
      Ein $test[$i] .= ''; reicht nicht. PHP erkennt das das Element nicht verändert wird. Aber die Verkürzung um 1 Zeichen mit $test[$i] = substr($test[$i],0,-1); führt zu einen Speicherverbrauch in der Größenordnung von Variante 2.
      Wird vom array test nur 1 Element manipuliert führt das dagegen nur zu einer kaum messbaren Erhöhung des Speichers. Manipuliere ich 50% des Array ist der Zuwachs auch nur ca. 50%.

      Beim Ausdruck '97c2ca84-bcfe-4618-b8a3-4d404eead37a'.$i%1; in der Schleife erkennt PHP nicht das immer wieder die gleichen Elemente erzeugt werden und legt diese alle im Speicher ab.

      Wieder was dazugelernt. Das Alles spielt aber nur eine Rolle bei wirklich großen Arrays. Dort lohnt es sich dann aber auch mal genauer hinzuschauen was PHP wirklich macht.

      Kommentar


      • #4
        Für den Programmierer dürfte das wohl irrelevant sein. Das ist eine PHP-interne Ressourcenoptimierung. Ich würde Programmcode jedenfalls nicht basierend auf dieser interner Optimierung schreiben, da sich das von PHP-Version zu PHP-Version jederzeit wieder ändern kann.

        Kommentar


        • #5
          Zitat von jspit Beitrag anzeigen
          Mit "copy on write" verbinde ich folgenden Effekt:
          Ja schon klar. Das ist aber dasselbe in Grün. Du hast eine String Konstante im Code, die muss schon beim Parsen irgendwo auch im Speicher abgelegt werden. Warum dann nicht gleich nutzbar als zval und entsprechend referezieren?!
          Ich glaube das macht der opcache. Das Verhalten lässt sich auch bei sowas beobachten:

          PHP-Code:
          $a 'sehr langer string ... immer identisch';
          $b 'sehr langer string ... immer identisch';
          $c 'sehr langer string ... immer identisch';
          $d 'sehr langer string ... immer identisch'

          Zitat von jspit Beitrag anzeigen
          Das Alles spielt aber nur eine Rolle bei wirklich großen Arrays. Dort lohnt es sich dann aber auch mal genauer hinzuschauen was PHP wirklich macht.
          Wirklich große Arrays und PHP passen nicht zusammen (Anzahl der Elemente und mehrdimensional). Dieses all fits one "Array" in PHP fällt dir dabei auf die Füße und auch die SPL Varianten bringen es nicht. Ab ein gewissen Punkt ist eine sqlite in Memory Datenbank effizienter. (oder eine andere Sprache)

          Kommentar


          • #6
            Zitat von hellbringer Beitrag anzeigen
            Für den Programmierer dürfte das wohl irrelevant sein. Das ist eine PHP-interne Ressourcenoptimierung. Ich würde Programmcode jedenfalls nicht basierend auf dieser interner Optimierung schreiben, da sich das von PHP-Version zu PHP-Version jederzeit wieder ändern kann.
            Hab ich auch nicht empfohlen Programmcode auf Basis irgendwelcher interner Optimierungen zu schreiben. Die Tests zeigen mir aber auch, das wenn es bei großen Arrays zu Speicherproblemen kommt, man die Ursache nicht nur bei der Arrayerstellung suchen darf.
            Vom Grundsatz sollte der Programmierer bei Problemen mit großen Arrays überlegen ob es wirklich notwendig ist die Daten komplett im Speicher zu halten. Generatoren und Iteratoren sind zwei mögliche Alternativen die richtig angewendet den Speicher wenig beanspruchen.

            Edit: Bei großen Datenmengen sind Datenbanken die Lösung ganz klar.

            Kommentar

            Lädt...
            X