2

I am writing a unit test for my profiling code. In order to do so, I am writing some functions that will allocate memory and call 'sleep' in order to generate predictable memory and time results that I can test against.

The "allocate memory" part is turning out to be a bit tricky.

Without a 'malloc' type function, I have tried appending to a string: $myString .= 'x'; and appending to an array: $myArray[] = null;

But my results show that these structures do not allocate memory linearly on demand.

Your suggestions are appreciated!

kpatelPro
  • 287
  • 2
  • 10
  • FWIW, I learned after a bit that (in my test case) appending a character to a string was allocating a single byte on demand. The results were being obfuscated by a 72-byte per first-call to a function by some unknown implicit system (perhaps PHP itself). – kpatelPro May 23 '11 at 22:16
  • That said, as Tomalak mentions below, PHP's Memory Management can do whatever it wants, so it should never be assumed that the allocations will be carried out in this manner. – kpatelPro May 23 '11 at 22:19

2 Answers2

5

PHP is a high-level language. Memory management is left up to the engine. You cannot and should not attempt to work around this.

Instead profile things that are actually useful to profile in PHP, like real-life use of strings and arrays of stuff.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • I am not trying to work around PHP's memory management. But I do need to verify that I am processing profiling data correctly with a predictable test case. If you have another suggestion for a way to generate a predictable test case I would be happy to hear it. – kpatelPro May 23 '11 at 21:45
  • @kpatelPro: Sorry if I wasn't clear. Run your profiler over real usage of PHP, like calling functions and generating the strings that you need to use in your application. Allocating arbitrary blocks of memory is neither useful nor appropriate here. – Lightness Races in Orbit May 23 '11 at 21:48
  • I am writing code that generates reports from profiling data, and I am writing a unittest for that report generator. Part of the "unittest" requirement is that I run the profiler over code that has some sort of predictable results, including memory allocation from specific functions. So, it is useful for me. :) I welcome your response. – kpatelPro May 23 '11 at 22:06
  • @kpatelPro: Expecting predictable low-level behaviour from high-level code seems like a fool's errand to me. The whole point is that that is abstracted away from you. Good luck – Lightness Races in Orbit May 23 '11 at 22:11
2

Here is a test function that allocates memory in chunks into an a series of arrays until total memory limit is exhausted. Perhaps you can use a similar method to allocate memory as you like as well. Sort of like a mallaoc() C function...

On my web server I get these results...

Memory Test

Memory Limit: 536870912 
Initial memory usage: 637448 

Allocate 1 million single character elements to myArray0 
Current memory usage: 97026784 
Allocate 1 million single character elements to myArray1 
Current memory usage: 193415768 
Allocate 1 million single character elements to myArray2 
Current memory usage: 289804704 
Allocate 1 million single character elements to myArray3 
Current memory usage: 386193640 
Allocate 1 million single character elements to myArray4 
Current memory usage: 482582576 
Memory Test Complete

Total memory used: 482582576 
Average memory used per array in each of 5 arrays: 96389025 
Average memory used per character in each of 5 arrays: 96 
Remaining memory: 54288336

// This routine demonstrates how to get and use PHP memory_limit, memory_get_usage, variable array names, and array_fill
// to allocate large blocks of memory without exceeding php.ini total available memory
echo "<h2>Memory Test</h2>";

// Get total memory available to script
$memory_limit = get_memory_limit();
echo "Memory Limit: $memory_limit <br />";
$initMemory = $currentMemory = memory_get_usage();
echo "Initial memory usage: $initMemory <br /><br />";

// Start consuming memory by stuffing multiple arrays with an arbitrary character
$i =0;
while ( $currentMemory + ($currentMemory - $initMemory)/($i+1) <= $memory_limit) 
{       
    echo "Allocate 1 million single character elements to myArray$i <br />";
    ${myArray.$i} = array_fill(0, 1000000, "z");
    $currentMemory = memory_get_usage();
    echo "Current memory usage: $currentMemory <br />";
    $i++;
}
echo "<h2>Memory Test Complete</h2>";
echo "Total memory used: $currentMemory <br />";
$aveMemoryPerArray = (int)(($currentMemory - $initMemory)/$i);
echo "Average memory used per array in each of " .$i . " arrays: " . $aveMemoryPerArray . " <br />";    
echo "Average memory used per character in each of " . $i . " arrays: " . (int)($aveMemoryPerArray/1000000) . " <br />";
echo "Remaning memory: " . ($memory_limit - $currentMemory) . "<br />";

// Utility to convert php.ini memory_limit text string into an integer value in bytes
// Reference: http://stackoverflow.com/questions/10208698/checking-memory-limit-in-php
function get_memory_limit()
{
    $memory_limit = ini_get('memory_limit');
    if (preg_match('/^(\d+)(.)$/', $memory_limit, $matches)) {
        if ($matches[2] == 'M') {
            $memory_limit = $matches[1] * 1024 * 1024; // nnnM -> nnn MB
        } else if ($matches[2] == 'K') {
            $memory_limit = $matches[1] * 1024; // nnnK -> nnn KB
        }
    }
    return $memory_limit;
}