1

So, I am running a long-running script that is dealing with memory sensitive data (large amounts of it). I (think) I am doing a good job of properly destroying large objects throughout the long running process, to save memory.

I have a log that continuously outputs current memory usage (using memory_get_usage()), and I do not notice rises and drops (significant ones) in memory usage. Which tells me I am probably doing the right thing with memory management.

However, if I log on to the server and run a top command, I notice that the apache process that is dealing with this script never deallocates memory (at least visibly though the top command). It simply remains at the highest memory usage, even if the current memory usage reported by php is much, much lower.

So, my question is: are my attempts to save memory futile if the memory isnt really being freed back to the server? Or am I missing something here.

Thank you.

ps. using php 5.4 on linux

pps. For those who want code, this is a basic representation:

function bigData()
{
    $obj = new BigDataObj();
    $obj->loadALotOfData();

    $varA = $obj->getALotOfData();

    //all done
    $obj = NULL;
    $varA = NULL;
    unset($obj,$varA);
}

update: as hek2mgl recommended, I ran debug_zval_dump(), and the output, to me, seems correct.

function bigData()
{
    $obj = new BigDataObj();
    $obj->loadALotOfData();

    //all done
    $obj = NULL;

    debug_zval_dump($obj);

    unset($obj);

    debug_zval_dump($obj);
}

Output:

NULL refcount(2)

NULL refcount(1)
Kovo
  • 1,687
  • 14
  • 19
  • 1
    Are you calling memory_get_usage() with or without a TRUE argument? It makes quite a difference: using the TRUE argument returns the actual memory requested using emalloc; while a FALSE argument shows the blocks of memory used – Mark Baker Jul 23 '13 at 17:20
  • Rather than using PHP's own memory_get_usage() function to check memory usage, try using [xhprof](http://pecl.php.net/package/xhprof): the [GUI](http://blog.preinheimer.com/index.php?/archives/355-A-GUI-for-XHProf.html) makes it particularly easy to use – Mark Baker Jul 23 '13 at 17:43

1 Answers1

4

PHP has a garbage collector. It will free memory for variable containers which reference count is set to 0, meaning that no userland reference exists anymore.

I guess there are still references to variables which you might think to have cleaned. Need to see your code to show you what is the problem.

hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • PHP seems to collect garbage just fine, as I can see from the get_memory_usage() output. I know that these objects arent being referenced anymore since a lot of them are created and destroyed inside of a function any way. – Kovo Jul 23 '13 at 17:22
  • You say that the garbage collector is buggy? Use `debug_zval_dump($object)` to get sure that there are no references. – hek2mgl Jul 23 '13 at 17:23
  • I didnt say it was buggy :p I dont know if anything is buggy at all ,and Im just observing expected behaviour. Ill try that call. – Kovo Jul 23 '13 at 17:28
  • @hek2mgl wouldn't you need a refernce to pass it to the function :) – Orangepill Jul 23 '13 at 17:37
  • @Orangepill :) yes, of course. I just meant directly before `unset()` the refcount should be `1` in that test. (was too lazy to explain that, thx for asking) – hek2mgl Jul 23 '13 at 17:39
  • in this example, I get NULL refcount(2) : $obj = NULL; debug_zval_dump($obj); unset($obj); exit(); – Kovo Jul 23 '13 at 17:43
  • `refcount(2)` is the reason for your memory problems. how did you *cleaned* up? using `unset()`? – hek2mgl Jul 23 '13 at 17:44
  • Seems that the real code isn't that simple. The simple example should be garbage collected fine.. Also note that contexts which only exists inside a function/method (like in the simplified example) will be set to `refcount(0)` automatically right after the function has exited. No `unset()` is required – hek2mgl Jul 23 '13 at 17:47
  • Believe it or not, it is actually that simple. The block is inside of a function, and the object is a simpleXML object. I even moved this to the very last line of the method, and removed the return line. Still get refcount2 right before unset and right after the NULL. – Kovo Jul 23 '13 at 17:49
  • Actually, refcount(2) makes sense, since refcount also counts the variable being passed to debug_zval_dump – Kovo Jul 23 '13 at 18:00
  • no, this reference will not being counted. Try it with a simple var.. you'll get `refcount(1)` – hek2mgl Jul 23 '13 at 18:02
  • I see. I was just using the explanation given on php.net – Kovo Jul 23 '13 at 18:38
  • nice to see that you are a guy who is able to discover things by himself. also your assumption (that refcount will be one after calling the function wasn't so bad, although not being true) If you need further help just drop a comment here. (addressed to me, using @hek2mgl syntax. This way I will get noticed) – hek2mgl Jul 23 '13 at 19:06
  • @Kovo Btw, note that `xdebug` has features which can help you figuring out what is the memory problem – hek2mgl Jul 23 '13 at 19:18
  • I appreciate the back and forth. I assumed my assumption was correct (lol) when I saw a refcount of 1 AFTER the unset(); Any way, I suppose I will keep digging! – Kovo Jul 23 '13 at 19:28
  • PHP 5.3(4?)'s garbage collector is no longer strictly a reference counter. It can break circular references and garbage collect things like `a = &a`. – Marc B Jul 23 '13 at 20:31
  • @MarcB Nice that you've plugged into the discussion. :) Do you have a web reference? would like to learn more... (will google for myself until you can give the ultimate reference for that) – hek2mgl Jul 23 '13 at 20:34
  • It's in the GC discussion on the PHP site, and talked about how they detect circular references here: http://www.php.net/manual/en/features.gc.collecting-cycles.php – Marc B Jul 23 '13 at 20:37
  • @MarcB I'm beginning to read at the start of the chapter. It could be that my answer will be tomorrow. Just wanted to say: thanks for posting the link – hek2mgl Jul 23 '13 at 20:53