Why does this simple php script leak memory? - php

In hopes of trying to avoid future memory leaks in php programs (drupal modules, etc.) I've been messing around with simple php scripts that leak memory.
Could a php expert help me find what about this script causes the memory usage to continually climb?
Try running it yourself, changing various parameters. The results are interesting. Here it is:
<?php
function memstat() {
print "current memory usage: ". memory_get_usage() . "\n";
}
function waste_lots_of_memory($iters) {
$i = 0;
$object = new StdClass;
for (;$i < $iters; $i++) {
$object->{"member_" . $i} = array("blah blah blha" => 12345);
$object->{"membersonly_" . $i} = new StdClass;
$object->{"onlymember"} = array("blah blah blha" => 12345);
}
unset($object);
}
function waste_a_little_less_memory($iters) {
$i = 0;
$object = new StdClass;
for (;$i < $iters; $i++) {
$object->{"member_" . $i} = array("blah blah blha" => 12345);
$object->{"membersonly_" . $i} = new StdClass;
$object->{"onlymember"} = array("blah blah blha" => 12345);
unset($object->{"membersonly_". $i});
unset($object->{"member_" . $i});
unset($object->{"onlymember"});
}
unset($object);
}
memstat();
waste_a_little_less_memory(1000000);
memstat();
waste_lots_of_memory(10000);
memstat();
For me, the output is:
current memory usage: 73308
current memory usage: 74996
current memory usage: 506676
[edited to unset more object members]

unset() doesn't free the memory used by a variable. The memory is freed when the "garbage collector" (in quotes since PHP didn't have a real garbage collector before version 5.3.0, just a memory free routine which worked mostly on primitives) sees fit.
Also, technically, you shouldn't need to call unset() since the $object variable is limited to the scope of your function.
Here is a script to demonstrate the difference. I modified your memstat() function to show the memory difference since the last call.
<?php
function memdiff() {
static $int = null;
$current = memory_get_usage();
if ($int === null) {
$int = $current;
} else {
print ($current - $int) . "\n";
$int = $current;
}
}
function object_no_unset($iters) {
$i = 0;
$object = new StdClass;
for (;$i < $iters; $i++) {
$object->{"member_" . $i}= array("blah blah blha" => 12345);
$object->{"membersonly_" . $i}= new StdClass;
$object->{"onlymember"}= array("blah blah blha" => 12345);
}
}
function object_parent_unset($iters) {
$i = 0;
$object = new StdClass;
for (;$i < $iters; $i++) {
$object->{"member_" . $i}= array("blah blah blha" => 12345);
$object->{"membersonly_" . $i}= new StdClass;
$object->{"onlymember"}= array("blah blah blha" => 12345);
}
unset ($object);
}
function object_item_unset($iters) {
$i = 0;
$object = new StdClass;
for (;$i < $iters; $i++) {
$object->{"member_" . $i}= array("blah blah blha" => 12345);
$object->{"membersonly_" . $i}= new StdClass;
$object->{"onlymember"}= array("blah blah blha" => 12345);
unset ($object->{"membersonly_" . $i});
unset ($object->{"member_" . $i});
unset ($object->{"onlymember"});
}
unset ($object);
}
function array_no_unset($iters) {
$i = 0;
$object = array();
for (;$i < $iters; $i++) {
$object["member_" . $i] = array("blah blah blha" => 12345);
$object["membersonly_" . $i] = new StdClass;
$object["onlymember"] = array("blah blah blha" => 12345);
}
}
function array_parent_unset($iters) {
$i = 0;
$object = array();
for (;$i < $iters; $i++) {
$object["member_" . $i] = array("blah blah blha" => 12345);
$object["membersonly_" . $i] = new StdClass;
$object["onlymember"] = array("blah blah blha" => 12345);
}
unset ($object);
}
function array_item_unset($iters) {
$i = 0;
$object = array();
for (;$i < $iters; $i++) {
$object["member_" . $i] = array("blah blah blha" => 12345);
$object["membersonly_" . $i] = new StdClass;
$object["onlymember"] = array("blah blah blha" => 12345);
unset ($object["membersonly_" . $i]);
unset ($object["member_" . $i]);
unset ($object["onlymember"]);
}
unset ($object);
}
$iterations = 100000;
memdiff(); // Get initial memory usage
object_item_unset ($iterations);
memdiff();
object_parent_unset ($iterations);
memdiff();
object_no_unset ($iterations);
memdiff();
array_item_unset ($iterations);
memdiff();
array_parent_unset ($iterations);
memdiff();
array_no_unset ($iterations);
memdiff();
?>
If you are using objects, make sure the classes implements __unset() in order to allow unset() to properly clear resources. Try to avoid as much as possible the use of variable structure classes such as stdClass or assigning values to members which are not located in your class template as memory assigned to those are usually not cleared properly.
PHP 5.3.0 and up has a better garbage collector but it is disabled by default. To enable it, you must call gc_enable() once.

memory_get_usage() "Returns the amount of memory, in bytes, that's currently being allocated to your PHP script."
That's the amount of memory allocated to the process by the OS, not the amount of memory used by assigned variables. PHP does not always release memory back to the OS -- but that memory can still be re-used when new variables are allocated.
Demonstrating this is simple. Change the end of your script to:
memstat();
waste_lots_of_memory(10000);
memstat();
waste_lots_of_memory(10000);
memstat();
Now, if you're correct, and PHP is actually leaking memory, you should see memory useage grow twice. However, here's the actual result:
current memory usage: 88272
current memory usage: 955792
current memory usage: 955808
This is because memory "freed" after the initial invocation of waste_lots_of_memory() is re-used by the second invocation.
In my 5 years with PHP, I've written scripts that have processed millions of objects and gigabytes of data over a period of hours, and scripts that have run for months at a time. PHP's memory management isn't great, but it's not nearly as bad as you're making it out to be.

memory_get_usage reports how much memory php has allocated from the os. It doesn't necessarily match the size of all variables in use. If php has a peak use of memory, it may decide not to return the unused amount of memory right away. In your example, the function waste_a_little_less_memory unsets unused variables over time. So the peak usage is relatively small. The waste_lots_of_memory builds up a lot of variables (=lots of used memory) before deallocating it. So the peak usage is much larger.

My understanding of memory_get_usage() is that it's output can depend on a wide range of operating system and version factors.
More importantly, unsetting a variable does not instantly free it's memory, deallocate it from the process, and give it back to the operating system (again, characteristics of this operation are operating system dependent).
In short, you probably need a more complicated setup to look at memory leaks.

I'm not sure about the exact workings of it in PHP, but in some other languages an object containing other objects, when set to null, does not inherently set the other objects to null. It terminates the reference to those objects, but as PHP does not have "garbage collection" in a Java sense, the sub-objects exist in memory until they are removed individually.

memory_get_usage() does not returns the immediate memory usage, but stored memory to run the process.
IN the case of a huge array unset($array_a) will not release memory but consume more according to the memory_get_usage() in my system...
$array_a="(SOME big array)";
$array_b="";
//copy array_a to array_b
for($line=0; $line<100;$line++){
$array_b[$line]=$array_a[$line];
}
unset($array_a); //having this shows actually a bigger consume
print_r($array_b);
echo memory_get_usage();

Related

Which of the following is best for memory usage?

Which of the following is best for memory usage?
$a = new foo();
$username = $a->getuserName('username');
$b = new bar();
$b->validateUserName($username);
//OR
( new bar() )->validateUserName( (new foo() )->getuserName($username) );
Does storing an object in a variable increase memory usage?
does PHP treats other languages differently?
Someone can explain the management of PHP memory (should and should not)
To test memory usage you can use the next template:
<?php
$mem = 0; // create variable before "memory_get_usage()";
$mem = memory_get_usage();
// Place your code here
$mem = memory_get_usage() - $mem;
print ("Memory used: $mem");
For example I created the stub:
<?php
class foo {
function getuserName($a) {
return $a;
}
}
class bar {
function validateUserName($a) {
}
}
$mem = 0; // Allocate variable before "memory_get_usage()";
$mem = memory_get_usage();
$a = new foo();
$username = $a->getuserName('username');
$b = new bar();
$b->validateUserName($username);
$mem = memory_get_usage() - $mem;
print ("Memory used: $mem\r\n");
result on php 5.6.40 win x64 is 560 bytes.
If I change the code to your second variant
...
$mem = 0; // Allocate variable before "memory_get_usage()";
$mem = memory_get_usage();
// Note I've changed $username to 'username'
(new bar())->validateUserName( (new foo())->getuserName('username') );
$mem = memory_get_usage() - $mem;
print ("Memory used: $mem\r\n");
Now result is 0 bytes.
Let's see another variant:
...
function test() {
$a = new foo();
$username = $a->getuserName('username');
$b = new bar();
$b->validateUserName($username);
}
$mem = 0; // Allocate variable before "memory_get_usage()";
$mem = memory_get_usage();
test();
$mem = memory_get_usage() - $mem;
print ("Memory used: $mem\r\n");
Memory used: 64
Let's change the function to the second variant:
...
function test() {
(new bar())->validateUserName( (new foo())->getuserName('username') );
}
...
Now result again is 64 bytes.
And one more test:
...
$mem = 0; // Allocate variable before "memory_get_usage()";
$mem = memory_get_usage();
$a = new foo();
$username = $a->getuserName('username');
$b = new bar();
$b->validateUserName($username);
unset($a);
unset($b);
unset($username);
$mem = memory_get_usage() - $mem;
print ("Memory used: $mem\r\n");
Here result is 0 again.
From there I can assume, when you're creating global variables, they remains all the time, and object they are referencing cannot be garbage collected, so they remain in the memory. As soon as you unset variables, or declare them in a particular scope (function), or do not declare them at all - there is no difference in result. To see when object are destroyed and memory is freed you can add desctructors in the classes:
...
function __destruct() {
print "foo/bar destroyed\r\n";
}
...
Still, writing calls in one single line does not allocate unnecessary variables at all, thus improving execution time.
But my recommendation: do not bother with such optimizations in a language such as php. The language itself is not that fast and not that memory effective. For example, adding each item into array may cost more than 100 bytes of memory. Sparing several bytes by making code less readable is not worth it.

Why is $GLOBALS significately slower than global keywords?

I'Ve made a few test on global vs function parameter and the difference is futile.
But as i was testing stuff, i found that $GLOBALS is about 10% slower. than using function parameter or global keyword. Anyone care to explain why?
I wish to understand further the mechanism behind PHP. This so i can make better compromise on futur dev. Not that i ever use $GLOBALS except in some exception case.
$md5 = md5(1000000);
function byGlobal() {
global $md5;
$c = 0;
while( md5($c) != $md5 ){
$c++;
}
}
function superGlobal() {
$c = 0;
while( md5($c) != $GLOBALS[ 'md5' ] ){
$c++;
}
}
function asParam($md5) {
$c = 0;
while( md5($c) != $md5 ){
$c++;
}
}
$time3 = microtime(true);
asParam($md5);
echo (microtime(true) - $time3);
echo "<br/>";
$time1 = microtime(true);
byGlobal();
echo (microtime(true) - $time1);
echo "<br/>";
$time2 = microtime(true);
superGlobal();
echo (microtime(true) - $time2);
echo "<br/>";
I'm not arguing about function vs global or good practice. I really just wonder why so much difference. Ran the test 20 times and results are pretty much all consistent.
i move the calls up and down in the code to avoid caching influence.
I'm doing a million md5 iteration on each call so the server works a
load.
Time results are cosistent with other hashing function (tested sha1, crc32) and they are all in the same +10% slower)
Ran on a VM with PHP 5.4.16 on CentOs7.
1st run
as param : 0.8601s
as global : 0.8262s
as $GLOBALS : 0.9463s (more than 10% slower)
2nd run
as param : 0.8100s
as global : 0.8058s
as $GLOBALS : 0.9624s (more than 10% slower again)
Related studies : (mainely debate about global best practice, nothing about $GLOBALS vs global performance.
The advantage / disadvantage between global variables and function parameters in PHP?
php global variable overhead in a framework
Does using global create any overhead?
EDIT: New version, I made a mistake in the first one.
I've rewritten your tests, so it does test the things you want:
<?php
$value = 6235;
function byGlobal() {
global $value;
return $value++;
}
function superGlobal() {
return $GLOBALS['value']++;
}
function asParam($parameter) {
return $parameter++;
}
$time = microtime(true);
for ($i = 0;$i < 10000000;$i++) $value = asParam($value);
echo 'asParam: '.(microtime(true)-$time).'<br/>';
$time = microtime(true);
for ($i = 0;$i < 10000000;$i++) $value = byGlobal();
echo 'byGlobal: '.(microtime(true)-$time).'<br/>';
$time = microtime(true);
for ($i = 0;$i < 10000000;$i++) $value = superGlobal();
echo 'superGlobal: '.(microtime(true)-$time).'<br/>';
Example results for PHP 7.0.17 on CentOs7:
asParam: 0.43703699111938
byGlobal: 0.55213189125061
superGlobal: 0.70462608337402
and
asParam: 0.4569981098175
byGlobal: 0.55681920051575
superGlobal: 0.76146912574768
So, the superGlobal is the slowest, but not by that much. I guess the reason is that it is an array.
What I take away from this is that PHP is fast! I would not worry about the small differences in these tiny time slices. Having readable code is far more important. I my experiences the slowest thing in a website are the database queries.

PHP - Slow performance on function return assignment

As part of a project i came across this situation where inside a loop, i store the value of a function return.
This happened to be a bottleneck for the application, where big arrays would take forever to be processed.
To me, the assignment should be no reason for the incredible slow performance.
On the other hand, the same function call, with no assign on return gives much better performance.
Can you explain me why the first loop is much slower?
Output:
First took 1.750 sec.
Second took 0.003 sec.
class one {
private $var;
public function __construct() {
$this->var = array();
}
public function saveIteration($a) {
$this->var[] = $a;
return $this->var;
}
public function getVar() {
return $this->var;
}
}
$one = new one();
$time_start = microtime(true);
for ($i = 0; $i < 10000; $i++) {
$res = $one->saveIteration($i);
}
echo "First took " . number_format(microtime(true) - $time_start, 3) . " sec.";
$time_start = microtime(true);
for ($i = 0; $i < 10000; $i++) {
$one->saveIteration($i);
}
$res = $one->getVar();
echo "<br>Second took " . number_format(microtime(true) - $time_start, 3) . " sec.";
According to http://php.net/manual/en/functions.returning-values.php#99660 the array return value is not passed by-reference but by-value. Which means that a copy of the array is created (at the very least, when you change it again), which in turn needs time to actually create the copy (allocate memory, memcopy the data).
It probably have something to do with the fact that you're creating 10.000 arrays; each time incrementing the number of elements of the new array by 1 element.
My guess while you're inside the loop the local variable isn't freed on its own; Therefore I went ahead & tried freeing it using unset which got the results very close.
I know this is not a real world example; but in your code if you have something similar you could get away with it by just freeing (unsetting) the local variable once you're finished with it
here's your test code again:
class one {
private $var;
public function __construct() {
$this->var = array();
}
public function saveIteration($a) {
$this->var[] = $a;
return $this->var;
}
public function getVar() {
return $this->var;
}
}
$one = new one();
$time_start = microtime(true);
for ($i = 0; $i < 10000; $i++) {
$res = $one->saveIteration($i);
unset($res);
}
echo "First took " . number_format(microtime(true) - $time_start, 3) . " sec.".PHP_EOL;
$time_start = microtime(true);
for ($i = 0; $i < 10000; $i++) {
$one->saveIteration($i);
}
$res = $one->getVar();
echo "Second took " . number_format(microtime(true) - $time_start, 3) . " sec.".PHP_EOL;
Note: the only thing I've modify is adding unset in the first example
Result:
First took 0.068 sec.
Second took 0.062 sec.
#Jakumi made an excellent point. Since the values must be copied when you assign, 10,000 extra operations and a lot more memory are required in the first loop.
The difference between the two loops is actually much greater than your testing shows. Your comparison would be more fair if between the two tests, you reset with:
unset($one); $one = new one();
In your current test, the second loop is being executed while still holding the large array from the first loop in memory, so your results are not independent. See this modification

Memory leakage in php with three for loops

My script is a spider that checks if a page is a "links page" or is a "information page".
if the page is a "links page" then it continue in a recursive manner (or a tree if you will)
until it finds the "information page".
I tried to make the script recursive and it was easy but i kept getting the error:
Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to
allocate 39 bytes) in /srv/www/loko/simple_html_dom.php on line 1316
I was told i would have to use the for loop method because no matter if i use the unset() function the script won't free memory and i only have three levels i need to loop through so it makes sense. But after i changed the script the error occurs again, but maybe i can free
memory now?
Something needs to die here, please help me destruct someone!
set_time_limit(0);
ini_set('memory_limit', '256M');
require("simple_html_dom.php");
$thelink = "http://www.somelink.com";
$html1 = file_get_html($thelink);
$ret1 = $html1->find('#idTabResults2');
// first inception level, we know page has only links
if (!$ret1){
$es1 = $html1->find('table.litab a');
//unset($html1);
$countlinks1 = 0;
foreach ($es1 as $aa1) {
$links1[$countlinks1] = $aa1->href;
$countlinks1++;
}
//unset($es1);
//for every link in array do the same
for ($i = 0; $i < $countlinks1; $i++) {
$html2 = file_get_html($links1[$i]);
$ret2 = $html2->find('#idTabResults2');
// if got information then send to DB
if ($ret2){
pullInfo($html2);
//unset($html2);
} else {
// continue inception
$es2 = $html2->find('table.litab a');
$html2 = null;
$countlinks2 = 0;
foreach ($es2 as $aa2) {
$links2[$countlinks2] = $aa2->href;
$countlinks2++;
}
//unset($es2);
for ($j = 0; $j < $countlinks2; $j++) {
$html3 = file_get_html($links2[$j]);
$ret3 = $html3->find('#idTabResults2');
// if got information then send to DB
if ($ret3){
pullInfo($html3);
} else {
// inception level three
$es3 = $html3->find('table.litab a');
$html3 = null;
$countlinks3 = 0;
foreach ($es3 as $aa3) {
$links3[$countlinks3] = $aa3->href;
$countlinks3++;
}
for ($k = 0; $k < $countlinks3; $k++) {
echo memory_get_usage() ;
echo "\n";
$html4 = file_get_html($links3[$k]);
$ret4 = $html4->find('#idTabResults2');
// if got information then send to DB
if ($ret4){
pullInfo($html4);
}
unset($html4);
}
unset($html3);
}
}
}
}
}
function pullInfo($html)
{
$tds = $html->find('td');
$count =0;
foreach ($tds as $td) {
$count++;
if ($count==1){
$name = html_entity_decode($td->innertext);
}
if ($count==2){
$address = addslashes(html_entity_decode($td->innertext));
}
if ($count==3){
$number = addslashes(preg_replace('/(\d+) - (\d+)/i', '$2$1', $td->innertext));
}
}
unset($tds, $td);
$name = mysql_real_escape_string($name);
$address = mysql_real_escape_string($address);
$number = mysql_real_escape_string($number);
$inAlready=mysql_query("SELECT * FROM people WHERE phone=$number");
while($e=mysql_fetch_assoc($inAlready))
$output[]=$e;
if (json_encode($output) != "null"){
//print(json_encode($output));
} else {
mysql_query("INSERT INTO people (name, area, phone)
VALUES ('$name', '$address', '$number')");
}
}
And here is a picture of the growth in memory size:
I modified the code a little bit to free as much memory as I see could be freed.
I've added a comment above each modification. The added comments start with "#" so you could find them easier.
This is not related to this question, but worth mentioning that your database insertion code is vulnerable to SQL injection.
<?php
require("simple_html_dom.php");
$thelink = "http://www.somelink.co.uk";
# do not keep raw contents of the file on memory
#$data1 = file_get_contents($thelink);
#$html1 = str_get_html($data1);
$html1 = str_get_html(file_get_contents($thelink));
$ret1 = $html1->find('#idResults2');
// first inception level, we know page has only links
if (!$ret1){
$es1 = $html1->find('table.litab a');
# free $html1, not used anymore
unset($html1);
$countlinks1 = 0;
foreach ($es1 as $aa1) {
$links1[$countlinks1] = $aa1->href;
$countlinks1++;
// echo (addslashes($aa->href));
}
# free memroy used by the $es1 value, not used anymore
unset($es1);
//for every link in array do the same
for ($i = 0; $i <= $countlinks1; $i++) {
# do not keep raw contents of the file on memory
#$data2 = file_get_contents($links1[$i]);
#$html2 = str_get_html($data2);
$html2 = str_get_html(file_get_contents($links1[$i]));
$ret2 = $html2->find('#idResults2');
// if got information then send to DB
if ($ret2){
pullInfo($html2);
} else {
// continue inception
$es2 = $html2->find('table.litab a');
# free memory used by $html2, not used anymore.
# we would unset it at the end of the loop.
$html2 = null;
$countlinks2 = 0;
foreach ($es2 as $aa2) {
$links2[$countlinks2] = $aa2->href;
$countlinks2++;
}
# free memory used by $es2
unest($es2);
for ($j = 0; $j <= $countlinks2; $j++) {
# do not keep raw contents of the file on memory
#$data3 = file_get_contents($links2[$j]);
#$html3 = str_get_html($data3);
$html3 = str_get_html(file_get_contents($links2[$j]));
$ret3 = $html3->find('#idResults2');
// if got information then send to DB
if ($ret3){
pullInfo($html3);
}
# free memory used by $html3 or on last iteration the memeory would net get free
unset($html3);
}
}
# free memory used by $html2 or on last iteration the memeory would net get free
unset($html2);
}
}
function pullInfo($html)
{
$tds = $html->find('td');
$count =0;
foreach ($tds as $td) {
$count++;
if ($count==1){
$name = addslashes($td->innertext);
}
if ($count==2){
$address = addslashes($td->innertext);
}
if ($count==3){
$number = addslashes(preg_replace('/(\d+) - (\d+)/i', '$2$1', $td->innertext));
}
}
# check for available data:
if ($count) {
# free $tds and $td
unset($tds, $td);
mysql_query("INSERT INTO people (name, area, phone)
VALUES ('$name', '$address', '$number')");
}
}
Update:
You could trace your memory usage to see how much memory is being used in each section of your code. this could be done by using the memory_get_usage() calls, and saving the result to some file. like placing this below code in the end of each of your loops, or before creating objects, calling heavy methods:
file_put_contents('memory.log', 'memory used in line ' . __LINE__ . ' is: ' . memory_get_usage() . PHP_EOL, FILE_APPEND);
So you could trace the memory usage of each part of your code.
In the end remember all this tracing and optimization might not be enough, since your application might really need more memory than 32 MB. I'v developed a system that analyzes several data sources and detects spammers, and then blocks their SMTP connections and since sometimes the number of connected users are over 30000, after a lot of code optimization, I had to increase the PHP memory limit to 768 MB on the server, Which is not a common thing to do.
If your operation requires memory and your server has more memory available, you can call ini_set('memory_limit', '128M'); or something similar (depending your memory requirement) to increase the amount of memory available to the script.
This does not mean you should not optimise and refactor your code :-) this is just one part.
The solution was to use the clear method such as:
$html4->clear(); a simple_html_dom method to clear memory When you are finished with the DOM element.
If you want to learn more, enter this website.
Firstly, let's turn this into a truly recursive function, should make it easier to modify the whole chain of events that way:
function findInfo($thelink)
{
$data = file_get_contents($thelink); //Might want to make sure that it's a valid link, i.e. that file get contents actually returned stuff, before trying to run further with it.
$html = str_get_html($data);
unset($data); //Finished using it, no reason to keep it around.
$ret = $html->find('#idResults2');
if($ret)
{
pullInfo($html);
return true; //Should stop once it finds it right?
}
else
{
$es = $html->find('table.litab a'); //Might want a little error checking here to make sure it actually found links.
unset($html); //Finished using it, no reason to keep it around
$countlinks = 0;
foreach($es as $aa)
{
$links[$countlinks] = $aa->href;
$countlinks++;
}
unset($es); //Finished using it, no reason to keep it around.
for($i = 0; $i <= $countlinks; $i++)
{
$result = findInfo($links[$i]);
if($result === true)
{
return true; //To break out of above recursive functions if lower functions return true
}
else
{
unset($links[$i]); //Finished using it, no reason to keep it around.
continue;
}
}
}
return false; //Will return false if all else failed, should hit a return true before this point if it successfully finds an info page.
}
See if that helps at all with the cleanups. Probably still run out of memory, but you shouldn't be holding onto the full html of each webpage scanned and what not with this.
Oh, and if you only want it to go only so deep, change the function declaration to something like:
function findInfo($thelink, $depth = 1, $maxdepth = 3)
Then when calling the function within the function, call it like so:
findInfo($html, $depth + 1, $maxdepth); //you include maxdepth so you can override it in the initial function call, like findInfo($thelink,,4)
and then do a check on depth vs. maxdepth at the start of the function and have it return false if depth is > than maxdepth.
If memory usage is your primary concern, you may want to consider using a SAX-based parser. Coding using a SAX parser can be a bit more complicated, but it's not necessary to keep the entire document in memory.

Does PHP take RAM when defining variable from variable and taking instance of object to another variable?

In case I have this code
<?php
$array = array();
for ($i=1;$i<100000;$i++){
$array[$i] = md5(rand(0,9999999999999999));
}
$array2 = $array;
$array takes about 0.5MB RAM, let's say. Does PHP proccess take about 1.0MB RAM with $array2 = $array; ? and in this case
<?php
class rand{
public $array;
function rand(){
$this->array = array();
for ($i=1;$i<100000;$i++){
$this->array[$i] = md5(rand(0,9999999999999999));
}
}
}
$class = new rand();
$class2 = $class;
$class takes about 0.5MB RAM, let's say
. Does PHP proccess take 1.0MB with $class2 = $class?
is it same?
Tests:
First
Second
This is what the PHP manual in the reference section warns about: the Engine is smart enough. Setting the $array2 = $array; does not cause duplicate storage, as PHP recognizes they are still both the same. However, try a $array[2] = 'something;' after that. PHP detects the difference, and only then will copy the values.
<?php
$array = array();
for ($i=1;$i<100000;$i++){
$array[$i] = md5(rand(0,9999999999999999));
}
echo memory_get_usage().PHP_EOL;
$array2 = $array;
echo memory_get_usage().PHP_EOL;
$array['foo'] = 'bar';
echo memory_get_usage().PHP_EOL;
//17252052
//17252156
//23776652
Classes are references by default, and only a clone $object would result in 2 objects in PHP >= 5.

Categories