I was participating in a webinar with Zeev explaining the new implementation of PHP 7 and the improvements in memory management giving better performance. He pointed us to some blog posts, by Nikita Popov (@nikita_ppv), explaining improvements to the underlying structure of values, arrays, objects a.s.o.
In this blog post I want to summaries some of the changes and explain the difference in implementation.
In PHP 5 the values had three main data structures (_zval_struct, _zvalue_value, _zval_gc_info) and the way the data was set up all types took mostly the same amount of memory. All types were referenced and counted so garbage collection could be done. The values had extra garbage collection information outside of the main value structure. All in all this meant all data values took up 24 bytes of value + 32 bytes of garbage collection memory.
The new implementation uses another structure for the more involved types with reference counting and garbage collection included in the structs. And the easy types integer, double, string for example uses only the amount they allocate plus some type information. So an integer for example is saved with only 16 bytes of memory used.
Another strange data structure that has improved significantly is objects. To save an object in PHP 5 you needed to use _zval_struct, _zvalue_value, _zval_gc_info, _zend_object_value, _zend_object_store_bucket and _zend_object. All these abstractions made the structure quite hard to handle. For an example if you want to fetch one long property on a zvalue of type object you needed to look at the value _zval_struct->value->obj->handle->bucket->obj->object->properties_table->value->lval.
This structure has to many abstractions that in turn leads to harder code to read and probably more bugs. If we forget the strange structure and only focus on the memory footprint a simple object uses 136 bytes of data and has multiple reference counters for garbage collections for some odd reason.
The new implementation in PHP 7 takes care of these issues in a somewhat elegant way. Reference counting for these more complex types has been moved to the value objects. So the object has a reference counter struct, some handlers and the actual properties on the object. So the new lookup path would be something like _zval_struct->value->obj->properties_table->value->lval.
More over the basic object takes only 40 bytes of memory.
The old implementation of hash table used a simple hash to find a bucket place to store data. Then if you got a collision you had to link last entry in the bucket to it. The entry also had to have a previous link so removal could be performed efficiently. Lastly these links was duplicated for garbage collection reasons. So this structure ended up being quite heavy and memory intensive.
A quick calculation. Bucket 16 bytes, value 24 bytes with four links 32 bytes means that we use at least 72 bytes without any collisions, in practice 144 bytes is used and this with only one saved value in the table.
PHP 7 has a completely reworked structure. We have some meta data and order array of values. If this table is used as an array that is all we need. And if we need hashing functionality with keys we use an separate array.
To find a value in this hash array we first get a hash value. Then we modulus this with the size of the array to find the index. If this index is used we could implement collision by using another index and link it by adding this to the next property in the zvalue_value structure. It so happens that of the 16 bytes in this structure we only use 12 but still have to allocate 16 so the last 4 could be used for different tasks, for instance a next pointer. The hash array has a reference to the ordered bucket so we can retrieve our value. This new structure uses of 36 bytes.
The examples above could in some cases be worst case scenarios but the fact remains that the new PHP 7 implemenation is memory lean compared to PHP 5. And performance test in both benchmarks and WordPress tests have seen decreased times by 60 %.
If this entry seemed interesting then please read the references. Nikita goes in to a lot more detail about these changes.