I believe that the PHP GC works using reference counting (or at least, it used to). This means that circularly referenced objects may not be released until the end of the script.
You will not generally see freed memory be removed from the process's working set in "ps" or "top", but that should not be a problem (it's still freed internally).
PHP does appear to clean up objects as soon as they have no live references - but I'm not sure what its behaviour is for circularly referenced objects.
You can try to avoid circular references or have a special method on your object which unhooks references which could be circular.
There may be some built-in objects in PHP which utilise circular references (e.g. DOM?) - in which case you won't be able to do a lot about them.
The above script does not appear to be long-lived - it exits after 30 seconds. Is this what you had intended?
How did you determine that the above code "doesn't release the memory like it should"?
Mark