19

When I was doing a benchmark, I found that PHP 7 was using more memory than PHP 5.6.

So, I did a test. I ran a script containing only:

  $a=10;

and below are the results for the memory used when I used PHP CLI without any modules (php -n)

php 5.6 = 222600 Bytes
php 7.0 = 350448 Bytes

* PHP 5.6.23 (cli) (built: Jun 22 2016 12:13:15)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies 

* PHP 7.0.9 (cli) (built: Jul 20 2016 10:47:41) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies

Environment is

  • OS: window 10
  • Server : IIS (although I used the CLI, not the server), with fast cgi
  • machine : 64 bit
  • php-5.6.23-nts-Win32-VC11-x64
  • php-7.0.9-nts-Win32-VC14-x64

Can anyone explain why I got this result?


Additional Tests

Using this code, as suggested by @gordon,

$i=0;
while ($i++ < 100000) ;

php 5.6: 227408 bytes

php 7.0: 386640 bytes

I determined memory usage with this code:

echo PHP_EOL;
echo "Memory Usage :".memory_get_usage();
echo PHP_EOL;
echo "Real Memory Usage :".memory_get_usage(true);
echo PHP_EOL;
echo "Real Peak Memory Usage :".memory_get_peak_usage(true);
echo PHP_EOL;
echo "Peak Memory Usage :".memory_get_peak_usage();
Community
  • 1
  • 1
developerCK
  • 4,162
  • 3
  • 14
  • 33
  • 1
    Have you benchmarked it with some actual code? Even if a, more or less, empty script consumes 100k more doesn't tell us if that is true in a "real" scenario. Which is more interesting to know.. – Magnus Eriksson Sep 28 '16 at 07:15
  • Most likely, because PHP/7 optimisations have been targeted to complex scripts. One liners are very unlikely to cause a bottleneck. – Álvaro González Sep 28 '16 at 07:16
  • May be both versions enabled more or less modules but i am not sure – Gopal Joshi Sep 28 '16 at 07:30
  • @Gordon, actually there is differnce when i am benchmarking in applciation, so i thought to find out root cause, so started with a single line code. – developerCK Sep 28 '16 at 07:35
  • @Sameer i am running code using cli without loading any module. – developerCK Sep 28 '16 at 07:35
  • 6
    maybe, but the example you give here is contrived and very pointless. If you want to know why your app consumes more memory, make that into a question with details about the app. Profile your app. The way the question is phrased now insinuates that PHP7 *in general* eats more memory. That's a harmful suggestion to make because people will read that and take it for bare coin (after all, it was written on Stack Overflow), when in reality, PHP7 did numerous improvements to *reduce* memory usage. See for instance https://nikic.github.io/2014/12/22/PHPs-new-hashtable-implementation.html – Gordon Sep 28 '16 at 07:41
  • @Gordon, I really appreciate and looking forward for PHP7, even execution time has declined in PHP7, that is more beneficial for me. I am not pointing PHP 7 as well, i just want to know, what is the reason behind memory allocation, I searched a lot but could not find that's why i put the question. i put the example b/c any one can test that on their machine without any logic. – developerCK Sep 28 '16 at 07:56
  • It's likely just the bootstrapping of the interpreter/engine requiring more memory now. It's certainly not the $a=10; assignment you do. Compare https://3v4l.org/jmBha/perf#output for another contrived example. – Gordon Sep 28 '16 at 08:00
  • @RyanVincent, I am running code on cli, without loading any module, however, yes, i have default configuration 128 M for both – developerCK Sep 28 '16 at 08:31
  • I upvoted the question because I thought the scenario (overhead of an almost empty script) was interesting enough in terms of general culture (I know it isn't a real world scenario we should care about) and could use some answers about changes to PHP internals. I think the update to provide an entirely different script changes the meaning of the question and actually makes more vague and less answerable. – Álvaro González Sep 28 '16 at 10:50
  • @ÁlvaroGonzález, Thanks , i provide the update b/c Gordon mention that the basic one was not a real world scenario, while my concern was ,why memory consumption in php 7 is high, even a single variable is initialized, so i executed http://3v4l.org/jmBha/perf#output code at my machine to confirm more, so i added another piece of output as updated 2. I just wanted to make sure that it is not only variable initialization. My concern is just about how it is happening? – developerCK Sep 28 '16 at 11:14
  • If you're worried about an empty process using a hundred extra kilobytes your best bet is probably upgrading your server from a 1990s-era computer. – ceejayoz Sep 28 '16 at 15:13
  • @developerCK So, which of these for methods did you use? The correct one is `memory_get_usage()` (no "true" param, no "peak"). Otherwise you're either measuring details of the allocator or measuring the memory usage of the compiler. – NikiC Sep 28 '16 at 15:23
  • @NikiC, I understand, i gather the value from all four, and all results are higher in PHP7 compare to php 5.6, my concern is, if it is so for a variable initialization or loop process then what would happen for a complex page.and actually it is happening in one of my php page. – developerCK Sep 29 '16 at 06:17
  • @ceejayoz,, You might be right, just for curiosity, how up-gradation of server will help in this case. I understand i can increase memory, but on the other side, i will also try to improve the code so that it would consume less resource. – developerCK Sep 29 '16 at 06:20
  • @developerCK I'm not sure how you propose to improve the code, given that you're seeing differences with `$a=10;`. You're engaging in premature optimization. – ceejayoz Sep 29 '16 at 13:07
  • 3
    Well, the stem of different versions is fundamentally different, it is no surprise that a more advanced version of PHP is also bigger in size. More than that, the Zend Engine version is different, and even the VC version they are compiled on is different aswell. Nothing unexpected here so far, the question is, does it increase exponentially based on the size of your script too, or the difference remains similar? With such small codes it is hard to determine that. – Havenard Sep 29 '16 at 16:38
  • I still maintain it is interesting that you limit the memory allowed to 128 MB and PHP just ignores the setting. Why is that happening? You have explicitly set memory limits in your ini files? If you cannot get PHP to conform to memory limits then how do get meaningful interpretation of your memory usage results? i.e. what else is set to allow PHP to use whatever memory it wishes? At which point you are just looking at what PHP does when no restrictions are set? – Ryan Vincent Sep 29 '16 at 16:46
  • @Havenard, No it is not increasing exponentially , but yeah, i had a script in 5.6 it was taking ~628K, but in PHP 7 it took ~1069k. That's what worried me, and i tried to find the reason, I am not saying that this should not happen in php 7.0, but, due to curiosity, I just want to know what has changed in php5.6 and php7.0, that causing this. It would be very helpful, if I could find the reason, like it's due to compilation in vc 14, or zend engine, or PHP7.0 core itself. – developerCK Sep 29 '16 at 17:06
  • 3
    How do you know that PHP 7 isn't just being more efficient and just using more memory as it is faster and available? i.e. it is trying to help you. It is really clear that you haven't set any memory restrictions. So you are complaining about the default behaviour of the different PHP versions? – Ryan Vincent Sep 29 '16 at 18:02
  • @RyanVincent, Don't get me wrong Dude, I am not complaining, i am just trying to understand the things. Even in previous comments i have mentioned that it is more efficient in execution, saving response time means it can server more request per second, that is good for everyone, But, i just want to know the reason behind more memory usage. Even i am not confirmed that it is due to PHP7 it self. it might be windows binary of PHP 7 is doing such thing, I am not pointing out a objection, but just want to know the reason, so that i can follow the best. – developerCK Sep 30 '16 at 06:21
  • @RyanVincent Why do you think PHP is ignoring the memory limit? None of the figures quoted are anywhere near 128M. That setting doesn't mean "please use exactly 128M", it means "if you find you need more than 128M, abort the process immediately". Whether the ceiling (the memory limit) is 10 feet high, 100 feet high, or blown off by a hurricane makes no difference to measuring how tall somebody is (the memory usage of something much smaller than that limit). – IMSoP Oct 04 '16 at 10:22
  • 2
    My apologies, I didn't read your values properly. You are correct the values are less than 1 MB. I suspect all you are seeing is the 'housekeeping defaults' that PHP has when starting. I suspect the memory usage would make rather more sense when you start to allocate large arrays or lots of objects. i.e. entries of hundreds of thousands. You should then see that PHP 7 is more 'efficient'. i.e .less memory for the same data structures. – Ryan Vincent Oct 04 '16 at 10:33
  • A great tool to see differences between PHP versions is https://3v4l.org/ Also nice to compare gems like https://3v4l.org/cgOC3 – Rudie Oct 04 '16 at 21:36

4 Answers4

23

To understand the answer to your question - you need understand how PHP5 and PHP7 allocs memory.

PHP5 allocating memory "By Request" assuming by it's Zend Engine structure.

In PHP7 it's some optimizations made at this side, so on memory allocating "by the chunks"

  • On start it allocates large chunk of memory
  • On in-app allocation it allocates small chunk to avoid fragmentation

This differences makes very good increasing of performance (because of engine don't need allocate memory on runtime every time you need it and save some time on fragmentation), but it increases memory consumption for "very small" programs, which size is below than "chunk size".

And yes, PHP7 saves memory very much on large programs.

You may view all this differences in pictures below:

PHP memory allocation for large programs PHP memory allocation for small programs

Graphics builded with benchmark: 1.php

<?php

ini_set('memory_limit', '5G');
$a=range(1,$argv[1]);

echo PHP_EOL;
echo "Memory Usage :".memory_get_usage();
echo PHP_EOL;
echo "Real Memory Usage :".memory_get_usage(true);
echo PHP_EOL;
echo "Real Peak Memory Usage :".memory_get_peak_usage(true);
echo PHP_EOL;
echo "Peak Memory Usage :".memory_get_peak_usage();
echo PHP_EOL;

bench.sh

// Small programs
(for i in $(seq 0 5 5000);do php5 dev/Tools/mem/1.php $i|cut -f 2 -d:|sed -r 's/^$/;/g'|sed -r 's/([0-9]+)$/\1,/g'|tr -d '\n'; echo $i; done)|tr -d '\n'|sed -r 's/$/]/g'|sed -r 's/^;/[/g'>php5.m
(for i in $(seq 0 5 5000);do php dev/Tools/mem/1.php $i|cut -f 2 -d:|sed -r 's/^$/;/g'|sed -r 's/([0-9]+)$/\1,/g'|tr -d '\n'; echo $i; done)|tr -d '\n'|sed -r 's/$/]/g'|sed -r 's/^;/[/g'>php7.m
//Large Programs
(for i in $(seq 0 50 100000);do php5 dev/Tools/mem/1.php $i|cut -f 2 -d:|sed -r 's/^$/;/g'|sed -r 's/([0-9]+)$/\1,/g'|tr -d '\n'; echo $i; done)|tr -d '\n'|sed -r 's/$/]/g'|sed -r 's/^;/[/g'>php5.m    
(for i in $(seq 0 50 100000);do php dev/Tools/mem/1.php $i|cut -f 2 -d:|sed -r 's/^$/;/g'|sed -r 's/([0-9]+)$/\1,/g'|tr -d '\n'; echo $i; done)|tr -d '\n'|sed -r 's/$/]/g'|sed -r 's/^;/[/g'>php7.m

octave drawer

php7;php7=ans;
php5;php5=ans;
plot(php5(:,5)',[php5(:,1:4)';php7(:,1:4)']');
legend("PHP5 mgu", "PHP5 rmu", "PHP5 rpmu", "PHP5 pmu","PHP7 mgu", "PHP7 rmu", "PHP7 rpmu", "PHP7 pmu");

Read more

  1. Official PHP7/PHP-NG presentation: https://drive.google.com/file/d/0B3UKOMH_4lgBUTdjUGxIZ3l1Ukk/view
  2. Official PHP7/PHP-NG internal changes description: https://wiki.php.net/phpng-int
  3. Official extension migration guide: https://wiki.php.net/phpng-upgrading
  4. Good articles from @NikiC: http://nikic.github.io/2015/05/05/Internal-value-representation-in-PHP-7-part-1.html and http://nikic.github.io/2015/06/19/Internal-value-representation-in-PHP-7-part-2
  5. PHP5 internal details: http://www.phpinternalsbook.com/
  6. Badoo PHP5->PHP7 success story with details: https://techblog.badoo.com/blog/2016/03/14/how-badoo-saved-one-million-dollars-switching-to-php7/
samayo
  • 13,907
  • 11
  • 78
  • 98
MobDev
  • 1,434
  • 15
  • 17
  • thanks for beautiful explanation, i am in need for this. can you pls share some references, where i can go through zend 2 and zend 3 memory allocation difference, like what is the minimum chunk size that php 7 allocate when starts. – developerCK Oct 05 '16 at 07:15
  • I will attach some references to my answer this evening. – MobDev Oct 05 '16 at 10:20
  • 1
    Added read-more links to description of PHP5/PHP7 internals which details my answer – MobDev Oct 05 '16 at 22:50
13

Your tests show more memory usage in PHP 7.0 because the testing code is very simple.

PHP 7.0 is known to use less memory (and be faster) that PHP 5.6 due to a radical rewrite of the internal ZEND Engine (the interpreter core)

As Gordon commented most likely the new features and improvements in PHP 7.0 require a "bootstrap" that result in negative results when tested on small pieces of code.

Let's try it with something more complex: build an array of 10.000 integers then sort it using Quicksort algorythm.

Here is the result I get:

PHP 7.0

Memory Usage: 1432752
Real Memory Usage: 4194304
Real Peak Memory Usage: 4194304
Peak Memory Usage: 3152360


PHP 5.6

Memory Usage: 2756744
Real Memory Usage: 4980736
Real Peak Memory Usage: 6029312
Peak Memory Usage: 5710464

And still a simple 20 lines quicksort is way far from real world applications with thousands of lines of codes, many classes declarations, many instances...

I have run the test on http://phptester.net

Below is the code

<?php
function quick_sort($array)
{
    $length = count($array);
    $pivot = $array[0];
    $left = $right = array();
    for($i = 1; $i < count($array); $i++)
    {
        if($array[$i] < $pivot)
        {
            $left[] = $array[$i];
        }
        else
        {
            $right[] = $array[$i];
        }
    }
    return array_merge(quick_sort($left), array($pivot), quick_sort($right));
}

$unsorted = array();
for($i=0;$i<10000;$i++)
{
    $unsorted[] = rand(1,1000000);
}

$sorted = quick_sort($unsorted);

$lf = "<br/>";

echo $lf;
echo "Memory Usage: ".memory_get_usage();
echo $lf;
echo "Real Memory Usage: ".memory_get_usage(true);
echo $lf;
echo "Real Peak Memory Usage: ".memory_get_peak_usage(true);
echo $lf;
echo "Peak Memory Usage: ".memory_get_peak_usage();
echo $lf;

Credit for the quicksort algorythm in PHP: http://andrewbaxter.net/quicksort.php

Community
  • 1
  • 1
Paolo
  • 13,439
  • 26
  • 59
  • 82
  • Thanks @Paolo, I completely agree that it for large program it is more efficient, It would be very helpful if you pls share some information regarding bootstrapping in php7 and php5.6. it would really help me to understand php in better way. – developerCK Oct 05 '16 at 07:19
9

Upfront I want to say that if you see higher reported memory usage in PHP 7 on real code, the most likely cause is that PHP 7 will report memory usage of mysqlnd buffered queries as part of the memory usage. In PHP 5 this memory usage was not reported (but of course the memory was still used). For large queries this can make a very substantial difference.

Now to your actual case, which is basically the memory usage of PHP immediately after request startup. The answer by MobDev already explains why there is a discrepancy in "real" memory usage, which is the memory usage metric which reports how much memory PHP's allocator has requested from the system allocator of kernel. As MobDev points out PHP 7 will allocate memory in much larger chunks (2MB) and is also more aggressive about caching allocated chunks.

However this does not explain the discrepancy in "non-real" memory usage, which does not take these allocator details into account. It is easy to check whether exactly the memory goes by using a memory profiler, e.g. by running PHP through USE_ZEND_ALLOC=0 valgrind --tool=massif. The USE_ZEND_ALLOC=0 part instructs PHP to not use its own allocator.

First of all this will show you that the actual memory usage and the memory usage reported by PHP differ quite significantly. Massif will show 3.2MB usage for PHP 5.6 and 2.3MB for PHP 7. The reason is that PHP only reports memory that goes through it's own allocator (ZMM), while many structures that survive across multiple request are not allocated using it.

The largest allocations going through the system allocator (thus not reported in the memory usage) are:

                       | PHP 5.6 | PHP 7
interned string buffer | 1 MB    | 150 KB + strings
GC buffer              | 320 KB  | 320 KB
internal classes/funcs | >1.3 MB | >0.5 MB

The "internal classes/funcs" number is a crude lower bound, because there are many small allocations involved here which are hard to count. One main difference is visible, which is that PHP 7 does not use a fixed interned string buffer (the listed size is the for the hashtable buffer I'm seeing, which does not include the size of the strings themselves).

However, this still doesn't answer the question of the actually reported memory usage. In this case the largest allocations are:

             | PHP 5.6 | PHP 7
VM stack     | 130 KB  | 256 KB
Object store | 64 KB   | (8 KB)
CG arena     | ---     | 64 KB

There are a couple of differences here. The main one is that PHP 7 uses a larger VM page size (about twice as large). Additionally PHP 7 uses an arena to store certain structures (like user functions), which starts off with a default size of 64KB. On the other hand the size of the object store buffer is significantly smaller in PHP 7.

So essentially the TL;DR answer is that PHP 7 uses a larger VM stack page size.

Community
  • 1
  • 1
NikiC
  • 95,987
  • 31
  • 182
  • 219
-6

Php 5.6 requires less bytes as compared to Php 7.0.

  • I thought PHP7 was more memory efficient? – halfer Oct 04 '16 at 23:18
  • Yes @halfer PHP7 is more efficient, if you go through from medium to large scale usage, if you store 100000 value, from 1-100000 in array and do some operation, you will find the major difference. – developerCK Oct 05 '16 at 07:14