Session - Größenbeschränkungen?
MB
- php
1 Christian Seiler0 Tom0 Christian Seiler0 Tom0 dedlfix0 Christian Seiler0 Tom0 dedlfix
Für das Session-Array gibt es doch sicherlich Beschränkungen, was die Größe, Länge o.ä. angeht. Wo schau ich nach wie groß so eine Session werden darf?
Gruß
MB
Hi,
Für das Session-Array gibt es doch sicherlich Beschränkungen, was die Größe, Länge o.ä. angeht. Wo schau ich nach wie groß so eine Session werden darf?
Naja, Du hast eigentlich nur Einschränkungen durch das normale PHP-Memory-Limit: Das Array muss zwei Mal in das Memory-Limit passen (einmal unserialisiert, einmal serialisiert), damit es nicht knallt. Darüber hinaus gibt es keine prinzipiellen Beschränkungen, ab einer gewissen Größe wird halt der Seitenzugriff schnell sehr langsam.
Viele Grüße,
Christian
Hello,
Für das Session-Array gibt es doch sicherlich Beschränkungen, was die Größe, Länge o.ä. angeht. Wo schau ich nach wie groß so eine Session werden darf?
Naja, Du hast eigentlich nur Einschränkungen durch das normale PHP-Memory-Limit: Das Array muss zwei Mal in das Memory-Limit passen (einmal unserialisiert, einmal serialisiert), damit es nicht knallt. Darüber hinaus gibt es keine prinzipiellen Beschränkungen, ab einer gewissen Größe wird halt der Seitenzugriff schnell sehr langsam.
"Arrays" benötigen seeehr viel Platz in PHP. Außerdem sollte MB daran denken, auch Register_Long_Arrays auszuschalten, weil die Session (und auch alle anderen Superglobalen) sonst noch ein weiteres Mal al Globale Arrays im Speicher liegen.
Eine Sessiondatei sollte nach Möglichkeit nicht über 2MB haben. Das haben Dennis Riehle und ich mal so mit Try & Error ermittelt. Ab knapp 1MB wird es bei "normalen" Hosts allerdings schon merklich langsamer. Woran das genau liegt, weiß ich allerdings nicht, das Verhalten war nur auf diversen unterschiedlichen Hosts sehr ähnlich.
Liebe Grüße aus Syburg bei Dortmund
Tom vom Berg
Hallo Tom,
Außerdem sollte MB daran denken, auch Register_Long_Arrays auszuschalten, weil die Session (und auch alle anderen Superglobalen) sonst noch ein weiteres Mal al Globale Arrays im Speicher liegen.
Nein. $_SERVER und $HTTP_SERVER_VARS liegen nur einmal im Speicher und zeigen auf das gleiche. Der zusätzliche Speicherverbrauch durch $HTTP_SERVER_VARS ist *immer* höchstens ein paar Bytes für das Vorhandensein des Variablennamens in der globalen Symboltabelle.
Viele Grüße,
Christian
Hello,
Außerdem sollte MB daran denken, auch Register_Long_Arrays auszuschalten, weil die Session (und auch alle anderen Superglobalen) sonst noch ein weiteres Mal al Globale Arrays im Speicher liegen.
Nein. $_SERVER und $HTTP_SERVER_VARS liegen nur einmal im Speicher und zeigen auf das gleiche. Der zusätzliche Speicherverbrauch durch $HTTP_SERVER_VARS ist *immer* höchstens ein paar Bytes für das Vorhandensein des Variablennamens in der globalen Symboltabelle.
Ok, das habe ich nicht explizit ausprobiert. Wenn Du es sagst, glaube ich das jetzt einfach mal.
Aber $_SESSION und $HTTP_SESSION_VARS sind nicht dasselbe Objekt.
Und wie es mit $_POST und $HTTP_POST_VARS und mit $_GET und $HTTP_GET_VARS?
Liebe Grüße aus Syburg bei Dortmund
Tom vom Berg
Hallo Tom,
Aber $_SESSION und $HTTP_SESSION_VARS sind nicht dasselbe Objekt.
Doch, sind sie (naja, außer, dass sie ein Array und kein Objekt sind ;-)):
-------------------------------------- schnipp -----------------------------
christian@cobalt ~/dev/php5.2 $ gdb sapi/cli/php
GNU gdb 6.7.1
Copyright (C) 2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) break ZEND_ECHO_SPEC_CV_HANDLER
Breakpoint 1 at 0x837b871: file /home/christian/dev/php5.2/Zend/zend_vm_execute.h, line 19340.
(gdb) break ZEND_ECHO_SPEC_VAR_HANDLER
Breakpoint 2 at 0x8355b4e: file /home/christian/dev/php5.2/Zend/zend_vm_execute.h, line 7050.
(gdb) run
Starting program: /home/christian/dev/php5.2/sapi/cli/php
[Thread debugging using libthread_db enabled]
[New Thread 0xb769b6e0 (LWP 1604)]
<?php
session_start ();
echo $_SESSION;
echo $HTTP_SESSION_VARS;
?>
[Switching to Thread 0xb769b6e0 (LWP 1604)]
Breakpoint 2, ZEND_ECHO_SPEC_VAR_HANDLER (execute_data=0xbf969a54)
at /home/christian/dev/php5.2/Zend/zend_vm_execute.h:7050
7050 zend_op *opline = EX(opline);
(gdb) n
7053 zval *z = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
(gdb) n
7055 if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL &&
(gdb) print z
$1 = (zval *) 0xa37cfe4
(gdb) c
Continuing.
Array
Breakpoint 1, ZEND_ECHO_SPEC_CV_HANDLER (execute_data=0xbf969a54)
at /home/christian/dev/php5.2/Zend/zend_vm_execute.h:19340
19340 zend_op *opline = EX(opline);
(gdb) n
19343 zval *z = _get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC);
(gdb) n
19345 if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL &&
(gdb) print z
$2 = (zval *) 0xa37cfe4
-------------------------------------- schnapp -----------------------------
Wie man sehen kann, zeigen die Operhands der beiden echo-Opcodes beide auf die gleiche Variable, hier zufälligerweise an Speicherposition 0xa37cfe4.
Und wie es mit $_POST und $HTTP_POST_VARS und mit $_GET und $HTTP_GET_VARS?
Das gleiche wie mit $_SERVER, $_SESSION, etc.
Viele Grüße,
Christian
Hello Christian,
Aber $_SESSION und $HTTP_SESSION_VARS sind nicht dasselbe Objekt.
Doch, sind sie (naja, außer, dass sie ein Array und kein Objekt sind ;-)):
Ooops.
Das war dann aber nicht immer so, oder?
Ich meine mich noch daran erinnern zu können, dass eine Änderung in $HTTP_SESSION_VARS keine Änderung in $_SESSION verursacht hat, mit Ausnahme der Initialisierung durch session_start().
Oder habe ich das jetzt nur geträumt?
Das Testscript dafür habe ich allerdings noch wiedergefunden.
Eben hat es auch das von Dir erwartete Ergebnis gebracht auf meinem Xampp.
<?php ### speichernutzung.php ###
session_start();
echo "<pre>\n";
echo htmlentities(print_r($_SESSION,1));
echo htmlentities(print_r($HTTP_SESSION_VARS,1));
$_SESSION['meine_var'] = 'Hallo Tom';
$HTTP_SESSION_VARS['hallo'] = 'keine Ahnung';
echo htmlentities(print_r($_SESSION,1));
echo htmlentities(print_r($HTTP_SESSION_VARS,1));
echo "</pre>\n";
?>
Ich weiß nicht mehr, wann der zusätzliche Parameter in print_r eingeführt wurde. Aber aus der zeit wird es stammen.
Liebe Grüße aus Syburg bei Dortmund
Tom vom Berg
Hallo Tom,
Ich meine mich noch daran erinnern zu können, dass eine Änderung in $HTTP_SESSION_VARS keine Änderung in $_SESSION verursacht hat, mit Ausnahme der Initialisierung durch session_start().
Ich habe mir mal selbst PHP 4.1 kompiliert (das ist die erste Version, die $_SESSION kannte) und habe dort mir die Pointer auf $_SESSION und $HTTP_SESSION_VARS geben lassen:
------------------------------ schnipp -------------------------------------
christian@cobalt ~/dev/php-4.1.0 $ gdb ./php
GNU gdb 6.7.1
Copyright (C) 2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) break zend_execute.c:1223
Breakpoint 1 at 0x809bcc4: file ./zend_execute.c, line 1223.
(gdb) run
Starting program: /home/christian/dev/php-4.1.0/php
<?php session_start (); echo $_SESSION; echo $HTTP_SESSION_VARS; ?>
Breakpoint 1, execute (op_array=0x84dd484) at ./zend_execute.c:1223
1223 zend_print_variable(get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R));
(gdb) print Ts[opline->op1.u.var].var.ptr
$1 = (zval *) 0x84e1a7c
(gdb) c
Continuing.
X-Powered-By: PHP/4.1.0
Set-Cookie: PHPSESSID=e64b44618f825ca0d09502192dcc8891; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Content-type: text/html
Array
Breakpoint 1, execute (op_array=0x84dd484) at ./zend_execute.c:1223
1223 zend_print_variable(get_zval_ptr(&opline->op1, Ts, &EG(free_op1), BP_VAR_R));
(gdb) print Ts[opline->op1.u.var].var.ptr
$2 = (zval *) 0x84e1a7c
(gdb) c
Continuing.
Array
Program exited normally.
------------------------------ schnapp -------------------------------------
Wie man hier sehen kann, ist der Zeiger für die Variable hier in beiden Fällen auf 0x84e1a7c, d.h. auf die gleiche Variable.
Viele Grüße,
Christian
Hello Christian,
vielen Dank für die viele Mühe.
Ich habe mir mal selbst PHP 4.1 kompiliert (das ist die erste Version, die $_SESSION kannte) und habe dort mir die Pointer auf $_SESSION und $HTTP_SESSION_VARS geben lassen:
[...]
Wie man hier sehen kann, ist der Zeiger für die Variable hier in beiden Fällen auf 0x84e1a7c, d.h. auf die gleiche Variable.
Dann kam das wohl in einem meiner wilden träume vor :-(
Aber wirklich wissen kann man es tatsächlich nur, wenn man sich so reinhängt, wie Du es jetzt getan hast.
Also Resumée: Selber Speicherbereich, also kein wesentlicher Mehrverbrauch bei Register_Long_Arrays = On zu befürchten, nur mehr Verwirrung, durch die unterschiedlichen Namensgültigkeiten.
Liebe Grüße aus Syburg bei Dortmund
Tom vom Berg
So viele Infos wollt ich gar nicht haben...
Also wären 100-200 Strings mit Länge <100 kein Thema?
So viele Infos wollt ich gar nicht haben...
Danke hättest aber trotzdem sagen können!
Hello,
So viele Infos wollt ich gar nicht haben...
Also wären 100-200 Strings mit Länge <100 kein Thema?
Aus dem Gedächtnis heraus nicht.
Ein "Array" benötigt pro Element <80 Bytes extra> und pro "Subarray" <180 Bytes extra>
Die Aussagen in <...> musst Du bitte gegen das Archiv validieren. Ich habe es schlichtweg vergessen, wieviel Bytes das ausmacht. Nicht, dass ich das nachher auch nur wieder geträumt habe!
Sollte sich darüber auch kein Thread mehr im Archiv finden lassen, versuche ich, mich in die "Upper World" zurückbeamen zu lassen. Versprochen!
Liebe Grüße aus Syburg bei Dortmund
Tom vom Berg
echo $begrüßung;
Außerdem sollte MB daran denken, auch Register_Long_Arrays auszuschalten, weil die Session (und auch alle anderen Superglobalen) sonst noch ein weiteres Mal al Globale Arrays im Speicher liegen.
Nein. $_SERVER und $HTTP_SERVER_VARS liegen nur einmal im Speicher und zeigen auf das gleiche. Der zusätzliche Speicherverbrauch durch $HTTP_SERVER_VARS ist *immer* höchstens ein paar Bytes für das Vorhandensein des Variablennamens in der globalen Symboltabelle.
Anfänglich ist das auch so. PHP legt bei einer Kopie nicht sofort die Daten doppelt an. Erst wenn die Werte in den Variablen "auseinanderlaufen" wird kopiert. Das passiert beispielsweise im Falle der GPC-Arrays, wenn man die Auswirkungen der Magic Quotes beseitigen will, und das erst im Script machen kann.
echo "$verabschiedung $name";
Hallo dedlfix,
Nein. $_SERVER und $HTTP_SERVER_VARS liegen nur einmal im Speicher und zeigen auf das gleiche. Der zusätzliche Speicherverbrauch durch $HTTP_SERVER_VARS ist *immer* höchstens ein paar Bytes für das Vorhandensein des Variablennamens in der globalen Symboltabelle.
Anfänglich ist das auch so. PHP legt bei einer Kopie nicht sofort die Daten doppelt an. Erst wenn die Werte in den Variablen "auseinanderlaufen" wird kopiert. Das passiert beispielsweise im Falle der GPC-Arrays, wenn man die Auswirkungen der Magic Quotes beseitigen will, und das erst im Script machen kann.
Ich habe das jetzt mit folgendem Testscript und Breakpoints beim echo-Sprachkonstrukt nochmal durchexerziert:
<?php
session_start ();
echo $_SESSION;
echo $HTTP_SESSION_VARS;
$_SESSION['a'] = 'b';
echo $_SESSION;
echo $HTTP_SESSION_VARS;
?>
Meine komplette Debugging-Sitzung:
------------------------------------- schnipp ------------------------------
GNU gdb 6.7.1
Copyright (C) 2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
seUsing host libthread_db library "/lib/libthread_db.so.1".
(gdb) set args sessiseq.php
(gdb) break ZEND_ECHO_SPEC_CV_HANDLER
Breakpoint 1 at 0x837b871: file /home/christian/dev/php5.2/Zend/zend_vm_execute.h, line 19340.
(gdb) break ZEND_ECHO_SPEC_VAR_HANDLER
Breakpoint 2 at 0x8355b4e: file /home/christian/dev/php5.2/Zend/zend_vm_execute.h, line 7050.
(gdb) run
Starting program: /home/christian/dev/php5.2/sapi/cli/php sessiseq.php
[Thread debugging using libthread_db enabled]
[New Thread 0xb76dc6e0 (LWP 18413)]
[Switching to Thread 0xb76dc6e0 (LWP 18413)]
Breakpoint 2, ZEND_ECHO_SPEC_VAR_HANDLER (execute_data=0xbfea97a4)
at /home/christian/dev/php5.2/Zend/zend_vm_execute.h:7050
7050 zend_op *opline = EX(opline);
(gdb) n
7053 zval *z = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
(gdb) n
7055 if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL &&
(gdb) print z
$1 = (zval *) 0xa44fb5c
(gdb) c
Continuing.
Array
Breakpoint 1, ZEND_ECHO_SPEC_CV_HANDLER (execute_data=0xbfea97a4)
at /home/christian/dev/php5.2/Zend/zend_vm_execute.h:19340
19340 zend_op *opline = EX(opline);
(gdb) n
19343 zval *z = _get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC);
(gdb) n
19345 if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL &&
(gdb) print z
$2 = (zval *) 0xa44fb5c
(gdb) c
Continuing.
Array
Breakpoint 2, ZEND_ECHO_SPEC_VAR_HANDLER (execute_data=0xbfea97a4)
at /home/christian/dev/php5.2/Zend/zend_vm_execute.h:7050
7050 zend_op *opline = EX(opline);
(gdb) n
7053 zval *z = _get_zval_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
(gdb) n
7055 if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL &&
(gdb) print z
$3 = (zval *) 0xa44fb5c
(gdb) c
Continuing.
Array
Breakpoint 1, ZEND_ECHO_SPEC_CV_HANDLER (execute_data=0xbfea97a4)
at /home/christian/dev/php5.2/Zend/zend_vm_execute.h:19340
19340 zend_op *opline = EX(opline);
(gdb) n
19343 zval *z = _get_zval_ptr_cv(&opline->op1, EX(Ts), BP_VAR_R TSRMLS_CC);
(gdb) n
19345 if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get_method != NULL &&
(gdb) print z
$4 = (zval *) 0xa44fb5c
(gdb) c
Continuing.
Array
Program exited normally.
(gdb) quit
------------------------------------- schnapp ------------------------------
Wie man sehen kann, zeigen beide Variablen vor- und nach der Änderung auf die gleiche Speicheradresse und sind somit identisch.
Und ja, PHP kennt copy-on-write, aber das ist hier irrelevant, da die Variablen sowieso immer die gleichen sind.
Viele Grüße,
Christian
echo $begrüßung;
Nein. $_SERVER und $HTTP_SERVER_VARS liegen nur einmal im Speicher und zeigen auf das gleiche. Der zusätzliche Speicherverbrauch durch $HTTP_SERVER_VARS ist *immer* höchstens ein paar Bytes für das Vorhandensein des Variablennamens in der globalen Symboltabelle.
Anfänglich ist das auch so. PHP legt bei einer Kopie nicht sofort die Daten doppelt an. Erst wenn die Werte in den Variablen "auseinanderlaufen" wird kopiert. Das passiert beispielsweise im Falle der GPC-Arrays, wenn man die Auswirkungen der Magic Quotes beseitigen will, und das erst im Script machen kann.
Ich habe das jetzt mit folgendem Testscript und Breakpoints beim echo-Sprachkonstrukt nochmal durchexerziert:
session_start ();
echo $_SESSION;
echo $HTTP_SESSION_VARS;
Bei Session liegt der Fall wieder etwas anders. Hier muss ja am Ende beides in einer Datei landen. Die EGPCS-Arrays sind aber definitiv nicht mehr die gleichen, wenn in einem von beiden geändert wird.
echo "$verabschiedung $name";
Nachtrag:
Wie gerade im Chat mir klar gemacht wurde, ist das bei $_SESSION eine Ausnahme, bei allen anderen $_GET / ... vs. $HTTP_GET_VARS tritt - sobald man eine Änderung macht - copy-on-write wirklich auf. Interessante Diskrepanz.
Viele Grüße,
Christian
Hello,
Anfänglich ist das auch so. PHP legt bei einer Kopie nicht sofort die Daten doppelt an. Erst wenn die Werte in den Variablen "auseinanderlaufen" wird kopiert.
Für welche Datentypen in welchen Situationen trifft das zu? Sind außer den Arrays auch andere davon betroffen?
Liebe Grüße aus Syburg bei Dortmund
Tom vom Berg
echo $begrüßung;
PHP legt bei einer Kopie nicht sofort die Daten doppelt an. Erst wenn die Werte in den Variablen "auseinanderlaufen" wird kopiert.
Für welche Datentypen in welchen Situationen trifft das zu? Sind außer den Arrays auch andere davon betroffen?
PHP macht das für alle Variablen unabhängig von ihrem Typ ($_SESSION und $HTTP_SESSION_VARS scheinen eine und die wohl auch die einzige Ausnahme zu sein).
Versteckt auf der Handbuchseite zu debug_zval_dump() findet sich ein Verweis auf ein PDF-Dokument auf Derik Rethans' Seiten: PHP References Article, das den internen Ablauf beschreibt.
Mit debug_zval_dump() kann man auch das Verhalten verfolgen:
$a = 42;
echo 'a: '; debug_zval_dump($a);
Ausgabe ist
a: long(42) refcount(2)
Der refcount ist aufgrund des Funktionsaufruf von debug_zval_dump() und der damit verbundenen (Nicht-)Kopie in die debug_zval_dump()-interne Parameter-Variable eins höher als das erwartete 1. Es gibt also zwei Verweise auf einen zval, PHPs Variablencontainer.
Ich füge zwei Variablen als direkte und indirekte Kopie von $a hinzu:
$b = $a;
$c = $b;
echo 'a: '; debug_zval_dump($a);
echo 'b: '; debug_zval_dump($b);
echo 'c: '; debug_zval_dump($c);
und sehe einen um 2 erhöhten refcount von 4 für alle drei Variablen:
a: long(42) refcount(4)
b: long(42) refcount(4)
c: long(42) refcount(4)
Ändere ich die Werte von $b und $c
$b = 23;
echo 'a: '; debug_zval_dump($a);
echo 'b: '; debug_zval_dump($b);
echo 'c: '; debug_zval_dump($c);
$c = 'foo';
echo 'a: '; debug_zval_dump($a);
echo 'b: '; debug_zval_dump($b);
echo 'c: '; debug_zval_dump($c);
verringert sich auch der refcount:
a: long(42) refcount(3)
b: long(23) refcount(2)
c: long(42) refcount(3)
a: long(42) refcount(2)
b: long(23) refcount(2)
c: string(3) "foo" refcount(2)
Somit gibt es nun drei separate zval-Container. Noch ein kleines Beispiel mit Arrays
$x = array($c, 'bar');
echo 'x: '; debug_zval_dump($x);
Hier sieht man den durch debug_zval_dump() verursachten refcount von 2 für $x, eine 2 für das $x[0], weil es eine Kopie ist, sowie eine 1 für das Element $x[1], das nur einen Verweis als Element von $x hat ...
x: array(2) refcount(2){
[0]=>
string(3) "foo" refcount(2)
[1]=>
string(3) "bar" refcount(1)
}
... solange man keine Kopien davon erstellt ...
$y = $x[1];
echo 'x: '; debug_zval_dump($x);
x: array(2) refcount(2){
[0]=>
string(3) "foo" refcount(2)
[1]=>
string(3) "bar" refcount(2)
}
... deren Wert nicht verändert wurde.
$x[1] = 'qux';
echo 'x: '; debug_zval_dump($x);
x: array(2) refcount(2){
[0]=>
string(3) "foo" refcount(2)
[1]=>
string(3) "qux" refcount(1)
}
echo "$verabschiedung $name";