Exessive memory usage if not explicitly disabled

My colleague wrote a script that ran out of available memory. I narrowed it down to the following basic test:

for ( $i = 0; $i <= 20; $i ++ ) { echo memory_get_usage(). '<br />'; $Survey = new Survey( 14 ); echo memory_get_usage(). '<br /><br />'; } exit('done'); 

This breaks in the third iteration:

 3116696 49123440 49123440 95518368 95518368 [E_ERROR] Allowed memory size of 134217728 bytes exhausted (tried to allocate 71 bytes) 

I managed to fix this by simply adding the unset() call to the loop:

 for ( $i = 0; $i <= 20; $i ++ ) { echo memory_get_usage(). '<br />'; $Survey = new Survey( 14 ); unset( $Survey ); echo memory_get_usage(). '<br /><br />'; } exit('done'); 

Now the script goes through 20 iterations nice and smooth, with relatively constant use of memory:

 3116816 49123488 49123488 50691656 50691656 51088912 51088912 51079064 51079064 50535368 50535368 50809296 50809296 51033392 51033392 51157208 51157208 50543856 50543856 50892760 50892760 51045160 51045160 51132688 51132688 50535968 50535968 50968632 50968632 51058080 51058080 51143304 51143304 50562136 50562136 51067432 51067432 51067768 51067768 51170824 51170824 50551712 done 

It bothers me! Shouldn't the garbage collector clear the object since the variable was overwritten? I am running PHP 5.3, so circular links cannot be the cause of this problem.

+6
source share
2 answers

Circular references can still be a problem in 5.3:

Cleaning problems

Although there is no longer a character in any area pointing to this structure, it cannot be cleared because the array element "1" still points to the same array. Since there is no external symbol indicating this, the user has no way to clear this structure; this way you get a memory leak. Fortunately, PHP will clear this structure data at the end of the request, but before that it happens in valuable memory space. This situation often happens if you implement parsing algorithms or other things in which you have a child, return the parent element. The same situation can happen with objects, of course, where this is most likely to happen, since objects are always implicitly used by reference.

There is probably some resource for storing memory inside Survey that takes up all this memory; the observed behavior should be a combination of the ref cycle and such a resource.

What exactly is in Survey ?

+4
source

The problem was caused by a combination of circular references and objects occupying 1/3 of the available memory each. Code change:

 for ( $i = 0; $i <= 20; $i ++ ) { echo memory_get_usage(). '<br />'; gc_collect_cycles(); echo memory_get_usage(). '<br />'; $Survey = new Survey( 14 ); echo memory_get_usage(). '<br /><br />'; } exit('done'); 

showed me:

 3116456 3116680 49123288 49123288 49123288 95518160 95518160 50452344 96236360 96236360 50365776 96261312 96261312 50477296 96348608 96348608 50453072 96349752 96349752 50478440 96364872 96364872 50468192 96365240 96365240 50478808 96370760 96370760 50473712 96366072 96366072 50474120 96371448 96371448 50479088 96375352 96375352 50478024 96376672 96376672 50480408 96374984 96374984 50476336 96373032 96373032 50478456 96372216 96372216 50475520 96371288 96371288 50477528 96378824 96378824 50483056 96383992 96383992 50482696 96376592 96376592 50475656 96378072 done 

You can clearly see that running the garbage collector manually frees up the memory occupied by the orphaned object. I think the problem is that the garbage collector did not have enough time because the objects were so large.

The simplest solution at the moment is to add an unset() call in the long run, although I will explore ways to make the Survey object more memory efficient.

Thanks to Jon and CodeCaster for pointing me in the right direction!

0
source

Source: https://habr.com/ru/post/900040/


All Articles