PHP memory overflow allowed memories size of solution

Source: Internet
Author: User
Tags vars

PHP appears with the following error: Allowed memory size of xxx bytes exhausted at xxx:xxx (tried to allocate xxx bytes)
In this regard, this site, http://nodonkey.iteye.com/blog/728223 has been described.
At the same time, there are http://hi.baidu.com/thinkinginlamp/blog/item/e400f819a3caab7cdbb4bd4e.html this article is also about this issue.
Why do we all say, here also to say, is not superfluous? Not really. The English text of this question is in: http://paul-m-jones.com/archives/262
As can be seen, it is necessary to summarize again.

If there is a recursive reference to the PHP object, a memory leak occurs. This bug has been around for a long time in PHP, so let's start by reproducing the bug:

PHP code
  1. <?php
  2. Class Foo {
  3. function __construct () {
  4. $this->bar = new bar ($this);
  5. }
  6. }
  7. Class Bar {
  8. function __construct ($foo) {
  9. $this->foo = $foo;
  10. }
  11. }
  12. for ($i = 0; $i < 100; $i + +) {  
  13. $obj = new Foo ();
  14. unset ($obj);
  15. Echo memory_get_usage (), "\ n";
  16. }
  17. ?>

Run the above code, you will find that the memory usage should have been the same, but in fact it is constantly increasing, unset not fully effective.
As we can see, the method given in the original English language is to call destructors manually. Why did you do it?
We give a new code, and note that the comments in the code explain the problem:

PHP code
  1. <?php
  2. Class Foo {
  3. function __construct () {
  4. //php5.3 Previous version, it is an elixir of immortality.  Because it was created, it references itself.
  5. //In fact, this class and the class referencing it cannot be unset as long as the class is referenced in the property of any of the external objects.
  6. //This is where we made a mistake here.
  7. $this->bar = new bar ($this);
  8. }
  9. function __destruct () {
  10. Echo (' Foo die--3--<br> ');
  11. unset ($this->bar);
  12. }
  13. /** 
  14. * Because we made a mistake here, we're here to clean up the mess. So, add a corpse function
  15. * This approach, that is, do not call __destruct outside, it looks very unsightly.
  16. * But adding this function has a big advantage. is to show the user that we need to kill it on our own initiative. Instead of waiting for it to die automatically.
  17. * If you don't want to, you can call __destruct directly outside
  18. */
  19. function Destroy ()
  20. {
  21. Echo (' destroy--1--<br> ');
  22. unset ($this->bar);
  23. }
  24. }
  25. Class Bar {
  26. function __construct ($foo) {
  27. $this->foo = $foo;
  28. }
  29. function __destruct () {
  30. Echo (' Bar die--2--<br> ');
  31. }
  32. }
  33. for ($i = 0; $i < 100; $i + +) {  
  34. Echo memory_get_usage (), "<br>";
  35. $obj = new Foo ();
  36. //Comment out, or let go of the line below the note and run it.  The results were later in this article.
  37. //We can find that if we do not bury the corpse, then PHP actively calls __destruct, then it is executed at the end of the program.
  38. //If we take the initiative, we can release the memory in time.
  39. $obj->destroy ();
  40. unset ($obj);
  41. }
  42. Echo Memory_get_usage (), "<br>";
  43. ?>

    We can find that when we comment out 42 lines in the above code [$obj->destroy ();] , the call in __destruct was delayed by PHP. That is, if the PHP object has recursive references, PHP does not release the memory in time. Even if you use unset, it is useless to want to force the release.
    We quote partial run results:
99616
99984
100352
100720
101088
Foo die--3--
Bar die--2- -
foo die--3--
Bar die--2--
Foo die--3--
Bar die--2--
Foo die--3--
Bar die--2--
Foo die--3--bar die--2--
    It can be seen that Foo,bar died at the end of the program, and that Foo died first and Bar died. This is because PHP is clear and you don't need them anymore.
    Once we manually invoke [$obj->destroy ();], because recursive references to PHP objects have been corrupted, unset works.
    We quote a partial run result:
64256
Destroy--1--
Bar die--2--
Foo die--3--
65008
Destroy-- *
Bar die--2--
foo die--3--
65008
Destroy--1--
Bar die--2--
Foo die--3--
    As you can see, Foo,bar is dead immediately after you call destroy, and memory is no longer growing.
    This bug is said to have been resolved in php5.3. If you are in php5.3, you can call gc_collect_cycles this function manually.
    If so, there is no difference between the fact that you manually add destroy to the class and let the user call.

Recursive references are often used. In particular, build a tree structure object with PHP. Note the link in the user comment in the original English text: http://www.alexatnet.com/node/73
The code given here:

PHP code
  1. Class Node {
  2. public $parentNode;
  3. public $childNodes = Array ();
  4. function Node () {
  5. $this->nodevalue = str_repeat (' 0123456789 ', 128);
  6. }
  7. }
  8. function CreateRelationship () {
  9. $parent = new Node ();
  10. $child = new Node ();
  11. $parent->childnodes[] = $child;
  12. $child->parentnode = $parent;
  13. }
  14. And then let's review the amount of memory allocated by this script after a calls to CreateRelationship function.
  15. Echo ' Initial: '. Number_format (Memory_get_usage (), 0, '. ', ', ' ).    "bytes\n";
  16. for ($i = 0; $i < 10000; $i + +) {    
  17. CreateRelationship ();
  18. }
  19. Echo ' Peak: '. Number_format (Memory_get_peak_usage (), 0, '. ', ', ' ).    "bytes\n";
  20. Echo ' End: '. Number_format (Memory_get_usage (), 0, '. ', ', ' ).   "bytes\n";

The output is:

initial:327,336 bytes
peak:35,824,176 bytes
end:35,823,328 bytes

The way the authors suggest is to increase the Destroy method,

PHP code
  1. Class Node {
  2. public $parentNode;
  3. public $childNodes = Array ();
  4. function Node () {
  5. $this->nodevalue = str_repeat (' 0123456789 ', 128);
  6. }
  7. function Destroy ()
  8. {
  9. $this->parentnode = null;
  10. $this->childnodes = Array ();
  11. }
  12. }
  13. function CreateRelationship () {
  14. $parent = new Node ();
  15. $child = new Node ();
  16. $parent->childnodes[] = $child;
  17. $child->parentnode = $parent;
  18. $parent->destroy ();
  19. }

In addition, the author also gives the solution in php5.3: Using the new function in php5.3, call gc_collect_cycles this function manually.

PHP code
    1. function CreateRelationship () {
    2. $parent = new Node ();
    3. $child = new Node ();
    4. $parent->childnodes[] = $child;
    5. $child->parentnode = $parent;
    6. Gc_collect_cycles ();
    7. }

At the same time, the author also tells us, call Gc_collect_cycles This function, we do not need to add additional destroy, but there are some drawbacks in performance.

We can also make further improvements to the code. That is to change to a static function. Specific as follows:

PHP code
    1. <?php
    2. Class Foo {
    3. function __construct () {
    4. //php5.3 Previous version, it is an elixir of immortality.  Because it was created, it references itself.
    5. //In fact, this class and the class referencing it cannot be unset as long as the class is referenced in the property of any of the external objects.
    6. //This is where we made a mistake here.
    7. $this->bar = new bar ($this);
    8. }
    9. function __destruct () {
    10. Echo (' Foo die--3--<br> ');
    11. unset ($this->bar);
    12. }
    13. /** 
    14. * Because we made a mistake here, we're here to clean up the mess. So, add a corpse function
    15. * This approach, that is, do not call __destruct outside, it looks very unsightly.
    16. * But adding this function has a big advantage. is to show the user that we need to kill it on our own initiative. Instead of waiting for it to die automatically.
    17. * If you don't want to, you can call __destruct directly outside
    18. * In fact, after doing this, there is no need to clean up the memory, write two lines of code, one line of code is enough.
    19. */
    20. static function Destroy ($obj)
    21. {
    22. Echo (' destroy--1--<br> ');
    23. unset ($obj->bar);
    24. unset ($obj);
    25. }
    26. }
    27. Class Bar {
    28. function __construct ($foo) {
    29. $this->foo = $foo;
    30. }
    31. function __destruct () {
    32. Echo (' Bar die--2--<br> ');
    33. }
    34. }
    35. for ($i = 0; $i < 100; $i + +) {  
    36. Echo memory_get_usage (), "<br>";
    37. $obj = new Foo ();
    38. //Use a static function instead, just one line here.
    39. Foo::d Estroy ($obj);
    40. }
    41. Echo Memory_get_usage (), "<br>";
    42. ?>

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.