What's better at freeing memory with PHP: unset() or $var = null

前端 未结 13 1981
陌清茗
陌清茗 2020-11-22 08:57

I realise the second one avoids the overhead of a function call (update, is actually a language construct), but it would be interesting to know if one is be

相关标签:
13条回答
  • 2020-11-22 09:31

    unset is not actually a function, but a language construct. It is no more a function call than a return or an include.

    Aside from performance issues, using unset makes your code's intent much clearer.

    0 讨论(0)
  • 2020-11-22 09:31

    Regarding objects, especially in lazy-load scenario, one should consider garbage collector is running in idle CPU cycles, so presuming you're going into trouble when a lot of objects are loading small time penalty will solve the memory freeing.

    Use time_nanosleep to enable GC to collect memory. Setting variable to null is desirable.

    Tested on production server, originally the job consumed 50MB and then was halted. After nanosleep was used 14MB was constant memory consumption.

    One should say this depends on GC behaviour which may change from PHP version to version. But it works on PHP 5.3 fine.

    eg. this sample (code taken form VirtueMart2 google feed)

    for($n=0; $n<count($ids); $n++)
    {
        //unset($product); //usefull for arrays
        $product = null
        if( $n % 50 == 0 )
        {
            // let GC do the memory job
            //echo "<mem>" . memory_get_usage() . "</mem>";//$ids[$n];
            time_nanosleep(0, 10000000);
        }
    
        $product = $productModel->getProductSingle((int)$ids[$n],true, true, true);
        ...
    
    0 讨论(0)
  • 2020-11-22 09:34

    It was mentioned in the unset manual's page in 2009:

    unset() does just what its name says - unset a variable. It does not force immediate memory freeing. PHP's garbage collector will do it when it see fits - by intention as soon, as those CPU cycles aren't needed anyway, or as late as before the script would run out of memory, whatever occurs first.

    If you are doing $whatever = null; then you are rewriting variable's data. You might get memory freed / shrunk faster, but it may steal CPU cycles from the code that truly needs them sooner, resulting in a longer overall execution time.

    (Since 2013, that unset man page don't include that section anymore)

    Note that until php5.3, if you have two objects in circular reference, such as in a parent-child relationship, calling unset() on the parent object will not free the memory used for the parent reference in the child object. (Nor will the memory be freed when the parent object is garbage-collected.) (bug 33595)


    The question "difference between unset and = null" details some differences:


    unset($a) also removes $a from the symbol table; for example:

    $a = str_repeat('hello world ', 100);
    unset($a);
    var_dump($a);
    

    Outputs:

    Notice: Undefined variable: a in xxx
    NULL
    

    But when $a = null is used:

    $a = str_repeat('hello world ', 100);
    $a = null;
    var_dump($a);
    Outputs:
    
    NULL
    

    It seems that $a = null is a bit faster than its unset() counterpart: updating a symbol table entry appears to be faster than removing it.


    • when you try to use a non-existent (unset) variable, an error will be triggered and the value for the variable expression will be null. (Because, what else should PHP do? Every expression needs to result in some value.)
    • A variable with null assigned to it is still a perfectly normal variable though.
    0 讨论(0)
  • 2020-11-22 09:34
    <?php
    $start = microtime(true);
    for ($i = 0; $i < 10000000; $i++) {
        $a = 'a';
        $a = NULL;
    }
    $elapsed = microtime(true) - $start;
    
    echo "took $elapsed seconds\r\n";
    
    
    
    $start = microtime(true);
    for ($i = 0; $i < 10000000; $i++) {
        $a = 'a';
        unset($a);
    }
    $elapsed = microtime(true) - $start;
    
    echo "took $elapsed seconds\r\n";
    ?>
    

    Per that it seems like "= null" is faster.

    PHP 5.4 results:

    • took 0.88389301300049 seconds
    • took 2.1757180690765 seconds

    PHP 5.3 results:

    • took 1.7235369682312 seconds
    • took 2.9490959644318 seconds

    PHP 5.2 results:

    • took 3.0069220066071 seconds
    • took 4.7002630233765 seconds

    PHP 5.1 results:

    • took 2.6272349357605 seconds
    • took 5.0403649806976 seconds

    Things start to look different with PHP 5.0 and 4.4.

    5.0:

    • took 10.038941144943 seconds
    • took 7.0874409675598 seconds

    4.4:

    • took 7.5352551937103 seconds
    • took 6.6245851516724 seconds

    Keep in mind microtime(true) doesn't work in PHP 4.4 so I had to use the microtime_float example given in php.net/microtime / Example #1.

    0 讨论(0)
  • 2020-11-22 09:37

    I still doubt about this, but I've tried it at my script and I'm using xdebug to know how it will affect my app memory usage. The script is set on my function like this :

    function gen_table_data($serv, $coorp, $type, $showSql = FALSE, $table = 'ireg_idnts') {
        $sql = "SELECT COUNT(`operator`) `operator` FROM $table WHERE $serv = '$coorp'";
        if($showSql === FALSE) {
            $sql = mysql_query($sql) or die(mysql_error());
            $data = mysql_fetch_array($sql);
            return $data[0];
        } else echo $sql;
    }
    

    And I add unset just before the return code and it give me : 160200 then I try to change it with $sql = NULL and it give me : 160224 :)

    But there is something unique on this comparative when I am not using unset() or NULL, xdebug give me 160144 as memory usage

    So, I think giving line to use unset() or NULL will add process to your application and it will be better to stay origin with your code and decrease the variable that you are using as effective as you can .

    Correct me if I'm wrong, thanks

    0 讨论(0)
  • 2020-11-22 09:37

    For the record, and excluding the time that it takes:

    <?php
    echo "<hr>First:<br>";
    $x = str_repeat('x', 80000);
    echo memory_get_usage() . "<br>\n";      
    echo memory_get_peak_usage() . "<br>\n"; 
    echo "<hr>Unset:<br>";
    unset($x);
    $x = str_repeat('x', 80000);
    echo memory_get_usage() . "<br>\n";      
    echo memory_get_peak_usage() . "<br>\n"; 
    echo "<hr>Null:<br>";
    $x=null;
    $x = str_repeat('x', 80000);
    echo memory_get_usage() . "<br>\n";      
    echo memory_get_peak_usage() . "<br>\n";
    
    echo "<hr>function:<br>";
    function test() {
        $x = str_repeat('x', 80000);
    }
    echo memory_get_usage() . "<br>\n";      
    echo memory_get_peak_usage() . "<br>\n"; 
    
    echo "<hr>Reasign:<br>";
    $x = str_repeat('x', 80000);
    echo memory_get_usage() . "<br>\n";      
    echo memory_get_peak_usage() . "<br>\n"; 
    

    It returns

    First:
    438296
    438352
    Unset:
    438296
    438352
    Null:
    438296
    438352
    function:
    438296
    438352
    Reasign:
    438296
    520216 <-- double usage.
    

    Conclusion, both null and unset free memory as expected (not only at the end of the execution). Also, reassigning a variable holds the value twice at some point (520216 versus 438352)

    0 讨论(0)
提交回复
热议问题