PHP memory overflow allowed memories size of solution

Source: Internet
Author: User

PHP memory overflow allowed memories size of solution Blog Category:
    • Php


============================allowed memory size of xxx bytes

Previously traced this problem, but at that time the tool was not very good, did not look so fine, this time the more fine, fixed my previous view

. So write a short article to summarize.

PHP occasionally explodes the following error allowed memory size of xxx bytes exhausted at xxx:xxx (tried to

Allocate xxx bytes)

Do not want to see the principle, directly jump to the end to see the summary.

This error message means that if the INI configuration memory_limit (memory limit) is greater than AG (allocated_memory), the error

AG (allocated_memory) + = RS;

if (AG (memory_limit) <ag (allocated_memory)) {

int php_mem_limit = AG (memory_limit);
AG (allocated_memory)-= RS;

if (EG (in_execution) & #038;& AG (memory_limit) +1048576 > AG (allocated_memory)) {

AG (Memory_limit) = AG (allocated_memory) + 1048576;

if (file) {
Zend_error (E_error, "allowed memory size of%d bytes exhausted
At%s:%d (tried to allocate%d bytes) ", Php_mem_limit, File, Lineno, s);
} else {
Zend_error (E_error, "allowed memory size of%d bytes exhausted
(tried to allocate%d bytes) ", Php_mem_limit, s);
}

} else {

if (file) {
fprintf (stderr, "allowed memory size of%d bytes exhausted
At%s:%d (tried to allocate%d bytes) n ", Php_mem_limit, File, Lineno, s);
} else {
fprintf (stderr, "allowed memory size of%d bytes exhausted
(tried to allocate%d bytes) n ", Php_mem_limit, s);
}

Exit (1);
}
}


Memory_limit is simple, it is the memory available in PHP. What is AG (allocated_memory)? is not already using the memory, uh,

Let's verify with the code

Php_function (memory_get_usage) {
Return_long (AG (allocated_memory));
}
This is clear, still do not understand, check PHP manual, see memory_get_usage instructions

Exactly when to set the AG (Allocated_memory), the specific code is not affixed, too cumbersome, is in the Emalloc function called the first paragraph

Code, look at the first line of code, where the RS is each time tried to allocate%d bytes corresponding s variable (the actual space you want to apply)

The align alignment, the specific calculation method: rs = (s+7) & ~0x7, that is, must be a multiple of 8, insufficient to complement, the advantage of doing so is in line with

64-bit machine requirements can be accelerated operations, such as S = 1, then the operation of Rs = 8, specifically, you can write a function in PHP to calculate

(0x7 is 16 binary notation).

Summary: Now that you know what is going on, it is good to solve, in the open –enable-memory-limit case, will make this error, the configuration text

Set the Memory_limit directly, or set the Ini_set (' memory_limit ', ' value ') in the code, the easy way

is to set the configuration file (such as php.ini)

And it is recommended to open –enable-memory-limit, if this does not open, PHP memory limit is in the "bare run" state, may appear

The name of the out of memory error.


One of the biggest benefits of using scripting languages is the automatic garbage collection mechanism (which frees up memory) that it has. You don't have to use the change

After doing any free memory processing, PHP will help you finish.

Of course, we can call the unset () function to free up memory as we wish, but this is not usually necessary.

In PHP, however, there is at least one case where memory is not automatically freed, even if it is manually called unset (). Details can be found in:

http://bugs.php.net/bug.php?id=33595.

Problem symptoms
If there is a mutually referenced relationship between two objects, such as "Parent-child object", calling Unset () on the parent object does not release the child

The memory of the parent object is referenced in the object (even if the parent object is garbage collected).

A little confused? Let's look at the following code:

<?php
Class Foo {
function __construct ()
{
$this->bar = new Bar ($this);
}
}

Class Bar {
function __construct ($foo = null)
{
$this->foo = $foo;
}
}

while (true) {
$foo = new Foo ();
Unset ($foo);
Echo Number_format (Memory_get_usage ()). "\ n";
}
?>
Run this code and you'll see that the memory usage is getting higher and higher until the light is exhausted.

...
33,551,616
33,551,976
33,552,336
33,552,696
PHP Fatal error:allowed Memory size of 33554432 bytes exhausted
(tried to allocate-bytes) in memleak.php on line 17
This is not a problem for most PHP programmers.

But if you use a lot of objects that are referenced in a long-running code, especially if the object is relatively large, the internal

The storage will be exhausted quickly.

Userland Solutions
Although somewhat tedious and not elegant, a solution was provided in the previously mentioned bugs.php.net link.

This scheme uses a destructor method to achieve the goal before releasing the object. The destructor method allows all internal parent objects

The reference is cleared, which means that the part of the memory that would otherwise overflow will be freed.

The following is the "repaired" code:

<?php
Class Foo {
function __construct ()
{
$this->bar = new Bar ($this);
}
function __destruct ()
{
unset ($this->bar);
}
}

Class Bar {
function __construct ($foo = null)
{
$this->foo = $foo;
}
}

while (true) {
$foo = new Foo ();
$foo->__destruct ();
Unset ($foo);
Echo Number_format (Memory_get_usage ()). "\ n";
}
?>
Notice the new Foo::__destruct () method, and the call to $foo->__destruct () before releasing the object. Now this

The code solves the problem of increasing memory usage, so that the code can work well.

PHP kernel solution?
Why is there a memory overflow happening? I am not proficient in the research of the PHP kernel, but I can be sure that this problem is related to reference counting

System.

Reference counts that reference $foo in the $bar do not decrement because the parent object $foo is freed, and PHP thinks you still need to $foo

Like, it will not release this part of the memory ... That's probably it.

I can really see my ignorance here, but the general meaning is: a reference count does not decrement, so some memory will never be released.

In the Bugs.php.net link mentioned earlier, I saw that the process of modifying garbage collection would sacrifice great performance because I counted the reference

Don't know much, so I think it's true.

Instead of changing the garbage collection process, why not use unset () to release the internal objects? (or when you release the object

Call __destruct ()? )

Perhaps the PHP kernel developer can make changes to this garbage collection mechanism here or elsewhere.

Update: Martin Fjordvald mentioned a patch written by David Wang for garbage collection in the comments (in fact it looks more

Like "a whole piece of cloth"--very big. See the CVS export information at the end of this message for details. ) does exist (an email) and is subject to

The attention of the PHP kernel development members. The problem is that the patch does not get much support in PHP5.3. I think a nice

The tradeoff is to call the __destruct () method in the object in the unset () function;

======================== Memory Overflow Solution

When doing statistical analysis of the data, often encounter large arrays, memory overflow may occur, here to share my solution. Or an example to illustrate the problem, as follows:

Assuming that the number of records stored in the log is 500,000, the solution is as follows:

Ini_set (' Memory_limit ', ' 64M '); Reset PHP can use a memory size of 64M, generally on the remote host is not able to modify the php.ini file, only through the program settings. Note: Under Safe_mode (Safe mode), the Ini_set fails

Set_time_limit (600);//Set timeout limit to 6 minutes

$farr = $Uarr = $Marr = $IParr = $data = $_sub = Array ();

$SPT = "[Email protected]#!$";

$root = "/data/webapps/visitlog";

$path = $dpath = $fpath = NULL;

$path = $root. " /". Date (" Y-m ", $timestamp);

$dpath = $path. " /". Date (" m-d ", $timestamp);

for ($j =0; $j <24; $j + +) {

$v = ($j < 10)? "0″. $j: $j;

$gpath = $dpath. " /". $v.". PHP ";

if (!file_exists ($gpath)) {

Continue

} else {

$arr = file ($gpath);////reads the files into the array

Array_shift ($arr);//Move out of the first unit-"<?php exit;? >

$farr = Array_merge ($farr, $arr);

Unset ($arr);

}

}

if (Empty ($this->farr)) {

echo "<p><center> no Related records! </center></p> ";

Exit

}

while (!empty ($farr)) {

$_sub = Array_splice ($farr, 0, 10000); 1000 $farr in each removal

For ($i =0, $scount =count ($_sub), $i < $scount; $i + +) {

$arr = Explode ($SPT, $_sub[$i]);

$Uarr [] = $arr [1]; Vurl

$Marr [] = $arr [2]; Vmark

$IParr [] = $arr [3]. "| $nbsp;". $arr [1]; Ip

}

Unset ($_sub);//run out of time to destroy

}

Unset ($farr);

Here, it is not difficult to see, on the one hand, we want to increase the size of the available PHP memory , on the other hand, as long as we find ways to batch processing , divide and conquer, the used variables are destroyed in time (unset) , there is generally no overflow problem .

In addition, in order to save PHP program memory loss, we should minimize the use of static variables, when the need for data reuse, you can consider using references (&). One more thing: Once the database operation is complete, close the connection immediately; When an object is exhausted, call the destructor (__destruct ()) in a timely manner.

============================unset destroys variables and frees memory issues


The PHP unset () function is used to clear, destroy variables, and we can destroy them with unset (). But at some point, using unset () does not achieve the memory that is consumed by destroying variables! Let's look at an example first:

<?php
$s =str_repeat (' 1 ', 255); Produces a string consisting of 255 1
$m =memory_get_usage (); Get Current memory consumption
Unset ($s);
$MM =memory_get_usage (); Unset () and then view the current memory consumption
echo $m-$mm;
?>

After the last output unset () takes up memory minus unset () before it takes up memory, if it is a positive number, then unset ($s) has destroyed $s from memory (or, after unset () the memory footprint is reduced), but I am under PHP5 and Windows platform, The resulting result is: 0. Does this mean that unset ($s) does not play the role of destroying the memory that the variable $s consumes? Let us make the following example:

<?php
$s =str_repeat (' 1 ', 256); Produces a string consisting of 256 1
$m =memory_get_usage (); Get Current memory consumption
Unset ($s);
$MM =memory_get_usage (); Unset () and then view the current memory consumption
echo $m-$mm;
?>

This example is almost identical to the example above, the only difference being that the $s consists of 256 1, which is a 1 more than the first example, and the result is: 272. Does this indicate that unset ($s) has destroyed the memory occupied by $s?
From the above two examples, we can draw the following conclusions:
Conclusionthe unset () function frees up memory space only if the value of the variable takes up more than 256 bytes of memory.

So is it possible to use unset to free up memory space as long as the value of the variable exceeds 256? Let's test it with one more example:

<?php
$s =str_repeat (' 1 ', 256); This is exactly the same as the second example.
$p =& $s;
$m =memory_get_usage ();
Unset ($s); Destroying $s
$MM =memory_get_usage ();
echo $p. ' <br/> ';
echo $m-$mm;
?>

Refresh the page, we see the first line has 256 1, the second row is 0, supposedly we have destroyed $s, and $p just reference $s variables, should be no content, in addition, unset ($s) before and after the memory consumption has not changed! Now let's do the following example:

<?php
$s =str_repeat (' 1 ', 256); This is exactly the same as the second example.
$p =& $s;
$m =memory_get_usage ();
$s =null; Set $s to null
$MM =memory_get_usage ();
echo $p. ' <br/> ';
echo $m-$mm;
?>

Now refresh the page, we see that the output $p has no content, unset () before and after the memory consumption of the difference is 272, that has cleared the memory of the variable occupied. The $s=null in this example can also be replaced with unset (), as follows:

<?php
$s =str_repeat (' 1 ', 256); This is exactly the same as the second example.
$p =& $s;
$m =memory_get_usage ();
Unset ($s); Destroying $s
Unset ($p);
$MM =memory_get_usage ();
echo $p. ' <br/> ';
echo $m-$mm;
?>

We destroy both $s and $p using unset (), and then the difference between memory consumption is 272, which means that memory can also be freed. So, we can get another conclusion:
Second, only when all variables that point to the variable, such as reference variables, are destroyed, the memory is freed.

PHP memory overflow allowed memories size of solution

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.