skip to Main Content

The very simple PHP code below works perfectly, I mean, it does nothing and at the same time it does not use almost any system memory.

<?php

set_time_limit(0); 
ini_set('memory_limit','-1');

for ($i=0;$i<100000000;$i++) {
        
    $bbb = function() {
    
        return true;

    };

    unset($bbb);
    
}

?>

While the code below is very similar BUT if you run it, after a few minutes you will crash your system because it will consume all your system RAM.

<?php

set_time_limit(0); 
ini_set('memory_limit','-1');

for ($i=0;$i<100000000;$i++) {
    
    eval('
    
        $bbb = function() {
        
            return true;
    
        };
    
    ');

    unset($bbb);
    
}

?>

My actual $bbb function is much more complex and it is a result of my AI output, so I really need to use eval in this case. I am totally aware of security implications.

I just wanna know how to solve this problem. How can I make PHP/APACHE release memory (the GC probably is the curlprit) in the second case?

NOTE: I am using Windows 10 with PHP 7.4

EDIT

As per suggestion of @Nigel Ren (which looks very good) I tried this:

<?php

set_time_limit(0); 
ini_set('memory_limit','-1');

for ($i=0;$i<100000000;$i++) {
    
    require("test.php");

    unset($bbb);
    
}

?>

And the "test.php" file has this:

<?php

$bbb = function() {

    return true;

};

?>

But this suggestion still consumes lots of memory, it’s not getting cleared! Even if I use gc_mem_caches(); GC is still not clearing memory. Maybe I understood something wrong from your suggestion @@Nigel Ren?

3

Answers


  1. Chosen as BEST ANSWER

    After lots of reseraching I discovered runkit7 is the way to go! It allows clearing RAM even from functions included/required/evaluated! You can use include/require/eval and it will wisely clean the memory footprint. It's a pretty awesome extension and I was amazed as soon as I tested it, my ram dropped 90% from the previous run I did without runkit7.


  2. See the last comment by Chris on this bug report.

    For posterity’s sake I’ll copy it here:

    I became interested by the eval() behavior recently, and I can confirm that the memory usage gets higher by the time of the execution.
    However it is not really a bug, but the way eval() is fundamentally written:

    • it creates a temp file with the code inside (sometimes it is stored in memory)
    • it then includes that temp file using a normal include() function

    As you can see, the more eval() you do, the more include() it will trigger, resulting in a memory usage that cannot be freed…

    So the reason your memory usages increases when using eval is that it’s including temporary files. There’s nu way to un-include files, so the more you use eval, the more memory you’re going to end up using.

    Disclaimer: the following is pure speculation, I have not verified if this will work

    As for a potential workaround to get around this issue, since you say you need to use eval, you could look into using the pcntl extension to fork a process.

    It’s probably going to be slower, but if you can fork the eval-ing piece of your code off to a separate process which can then terminate gracefully once finished, the "include" performed in that child process should be cleared up. That might be one way to limit the memory usage in your application.

    Login or Signup to reply.
  3. As a test, this code starts with a template for the source code in your first listing minus the definition but with a place holder to insert the code. The script just reads this file, replaces the marker with the AI script and writes a new file (abc1.php), then uses require to run the script. This removes any need for eval and the overheads associated with it…

    So abc.php is

    set_time_limit(0);
    ini_set('memory_limit','-1');
    
    for ($i=0;$i<10;$i++) {
        
        //#
        
        unset($bbb);
        
    }
    

    The bootstrap script is, where $aiSrc is the code you generate (note this also runs the function)…

    $src = file_get_contents("abc.php");
    $aiSrc = '$bbb = function() {
        
            echo "Hello";
    
        };
    
    $bbb();';
    
    $newSrc = str_replace("//#", $aiSrc, $src);
    file_put_contents("abc1.php", $newSrc);
    
    require"abc1.php";
    

    After this the script abc1.php contains…

    set_time_limit(0);
    ini_set('memory_limit','-1');
    
    for ($i=0;$i<10;$i++) {
        
        $bbb = function() {
        
            echo "Hello";
    
        };
    
    $bbb();
        
        unset($bbb);
        
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search