-
Notifications
You must be signed in to change notification settings - Fork 7.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unserialized objects use significantly more memory than ones created with the normal constructor #10126
Comments
One thing to note from the 3v4l results (and my own testing) is that from at least 5.2.1 through 7.3.11, unserialize_object_other has the same memory usage as unserialize_object (i.e., over-sized); only from 7.4.0 onward does it match new_object[_other]. |
Usually, declared object properties are stored in a C array ( |
And using |
No, not really. Re-opening, since this might deserve closer investigation.
This is because |
Hi @cmb69 thanks for considering this. In my use case, it is a difference betweem 500M or 1000M memory usage for the scipt. @MorganLOCode The workaround is pretty fast, fortunately. It does not slow down the script considerably, the difference is marginal. |
There are two places where the unserializer will allocate more memory when not using __unserialize. First place: php-src/ext/standard/var_unserializer.re Line 830 in 82b0537
The reason the table is extended beforehand, is because without it a nested deserialisation may cause an array resize, which will invalidate all pointers to the data. So by resizing beforehand all pointers will remain valid. One solution could be to shrink the hashtable after the deserialisation, but there is unfortunately no API for that. Second place: php-src/ext/standard/var_unserializer.re Line 825 in 82b0537
This was already hinted at by Christoph. The properties hash table is rebuilt and will be kept in memory. It seems like at least the first one should be doable to fix. The second one is for performance (speed) reasons. The reason it doesn't happen with __unserialize is because it overrides the default behaviour and instead collects the properties into an array: php-src/ext/standard/var_unserializer.re Lines 793 to 820 in 82b0537
|
Description
Consider the following code:
SomeClass
contains some data.new_object()
will create an instance, whileunserialize_object()
will unserialize an instance of exactly the same state (see$s1
). When an array of 50k elements is created with one or another, the output for memory usage is as follows:I.e. the 50k instances created with the constructor use 10M memory, while the unserialized ones 43M. It seems that some data structures that are used while unserializing are not freed. However, when unsetting
$arr
to destroy the instances, memory consumption will drop to 1M, as expected.Now consider
OtherClass
which has the__unserialize
method. Nothing fancy, it just sets the attributes as the default handler would do.new_object_other()
andunserialize_object_other()
replicate the same logic as explained above, but for the new class. Output in this case isThat is, memory consumption is the same regardless of how the objects are created.
Surplus memory usage grows with the number of attributes.
Tested with 8.1.2 and 8.2.0. Can also be seen on https://3v4l.org/ .
PHP Version
8.2.0
Operating System
No response
The text was updated successfully, but these errors were encountered: