Posts Tagged ‘php dynamic array’

While working on PureTextRender package, I realized some serious limits in PHP arrays. The mentioned package renders text into BMP images using pure PHP (no GD), and for that it requires a lot of arrays to be filled and traversed. The original package only supported small images due to typical PHP memory limit (128MB) though images were monochrome BMP! Before going any further, let's see some PHP benchmark code:

As you see, a thousand array elements take 94 Kilobytes of memory, resulting in 94 bytes per element on average. Lets do more experiments. I will omit the $startMemory and the line that echo's the memory difference in the rest of the examples in this article, and I'm running all this on a 64bit OS X:

As you can see, this example takes almost 50% more memory, though it is also populating a 1000 element array. It doesn't matter what the value is in the code, I can replace =$i with =0 and it would consume the same amount of memory. A simple explanation would be that the hash table used for storing array keys needs expansion over and over, and garbage collector doesn't get a chance to clean up before the end of the script, keeping the previous versions in place. An expansion policy of over 50% would result in about 50% overhead in memory usage.

Now the following code will only consume 20KB in spite of an expected 988 KB:

The reason for this behavior is that a single array of 100 elements is created in the internal expression, and assigned by reference to all outer 100 arrays, so the resulting memory consumption is (100+1)X instead of (100*100)X. Lets repeat all the experiments using SplFixedArray:

1

$a=new SplFixedArray(1000);//8.5703125 KB

$a=new SplFixedArray(1000); //8.5703125 KB

The above line only defines the fixed array, and the below code populated it as well:

Now this sample uses 55.6015625 KB of memory, making an average of 55 bytes per element. The ideal situation would be 8 bytes per element (as happens in the definition), since 64bit systems have 8 byte int elements, but the extra space is consumed by the hash table and its indices. As you can see, a 3-dimensional array of size 100 would quickly chomp up PHP memory and leave nothing to work with. Before going further with memory footprints, lets compare performance of SplFixedArray with native arrays:

Not bad at all! In fact array_fill is taking half the time of filling the array already. This means that assigning values to the array are much faster than expanding the hash table.
Overall, if it takes half a second to create, fill and traverse a one mega-entry array in PHP (~140MB). A typical web PHP setup has 128MB of memory limit (per instance) and 30 seconds of running time limit. They kinda match, because if you could come up with a faster storage that consumed more memory, you would be on a memory shortage, and if you came up with a denser storage, you would probably be too slow to fully utilize it. With all that being said, it appears that PHP focuses more on speed rather than memory, since most applications run more than one pass on pieces of their data.
Before going further, lets compare everything to an equivalent C code: