Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory leak? #9

Open
yangxikun opened this issue Dec 29, 2015 · 6 comments
Open

Memory leak? #9

yangxikun opened this issue Dec 29, 2015 · 6 comments
Labels

Comments

@yangxikun
Copy link

I use apache jemeter to make benchmark on the example server(with litter modify):

public function onRequest(Request $request, Socket $socket)
    {
        $data = sprintf(
            'Hello to %s:%d from %s:%d!',
            $socket->getRemoteAddress(),
            $socket->getRemotePort(),
            $socket->getLocalAddress(),
            $socket->getLocalPort()
        );

        $body = $request->getBody();

        if ($body->isReadable()) {
            $data .= "\n\n";
            do {
                $data .= (yield $body->read());
            } while ($body->isReadable());
        }

        $coroutine = Coroutine\create(function () {
            $client = new Client();
            $encoder = new Http1Encoder();

            // Connect to a google.com IP.
            // Use Icicle\Dns\connect() in icicleio/dns package to resolve and connect using domain names.
            $data = '';
            //Make a http request to another site
            try {
                $socket = (yield Icicle\Socket\connect('10.123.5.34', 80));

                /** @var \Icicle\Http\Message\Response $response */
                $response = (yield $client->request($socket, 'GET', 'an url', ['Cookie' => 'cookie=xxx']));

                $stream = $response->getBody();
                while ($stream->isReadable()) {
                    $data .= (yield $stream->read());
                }
            } catch (\Exception $e) {
                echo "Catch Exception by me : " . $e->getMessage() . "\n";
            }

            yield $data;
        });

        $coroutine->done(null, function (Exception $exception) {
            printf("Exception: %s\n", $exception);
        });
        $data .= (yield $coroutine);
        $sink = new MemorySink();
        yield $sink->end($data);

        $response = new BasicResponse(200, [
            'Content-Type' => 'text/plain',
            'Content-Length' => $sink->getLength(),
        ], $sink);

        yield $response;
    }

I found the memory use by the process is increase, and not decrease:

~/dev/icicle » ps -e -o 'pid,ppid,rsz,vsz,args' | grep php
114552   7223 125376 411320 php server.php

And there have many error output like:

Error when handling request from 192.168.103.1:51302: Failed to write to stream. Errno: 2; fwrite(): 2588 is not a valid stream resource

If I continue benchmark, will suffer a fatal error:

PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted at /home/rokety/software/php-5.6.15/Zend/zend_execute.h:187 (tried to allocate 130968 bytes) in /home/rokety/dev/icicle/vendor/icicleio/http/src/Driver/Encoder/Http1Encoder.php on line 70

Another, If I ctrl+c the server script, it print a memory leak message:

/home/rokety/software/php-5.6.15/Zend/zend_vm_execute.h(944) :  Freeing 0x7F8E06527168 (32 bytes), script=/home/rokety/dev/icicle/server.php
=== Total 1 memory leaks detected ===
@yangxikun yangxikun changed the title Memory Memory leak? Dec 29, 2015
@sagebind sagebind added the bug label Dec 29, 2015
@yangxikun
Copy link
Author

Maybe I have found the increase memory use reason: in the such EvIoManager class has properties like
private $events = []; or private $timers = [];

The framework stop some events or timers : $this->events[$id]->stop(); and $this->timers[$id]->stop();
But don't unset them(unset($this->events[$id]), unset($this->timers[$id])

@trowski
Copy link
Contributor

trowski commented Dec 31, 2015

I believe the memory leak was coming from the socket created by $socket = (yield Icicle\Socket\connect('10.123.5.34', 80)); not being closed (not calling $socket->close()). This leaves resources in the loop associated with that object. However, I see that being a common problem, so I updated the class extended by NetworkSocket so that the loop resources would be freed from the loop without calling close. Update to the latest version of icicleio/socket (should be able to just run composer update) and see if your code works without changes. Please let me know if you still are seeing memory leaks after updating.

@yangxikun
Copy link
Author

After update icicleio/socket, my code works!
However, there still something wrong:

  1. Under a high concurrent request, the allowed memory still exhausted(once this happen, the server is deny of service, and has to be kill -9). Is there a good practices to limit the concurrent connection number on the server script?
  2. zend engine still complain the memory leak:
~/dev/icicle » php server.php
^C[Fri Jan  1 07:41:41 2016]  Script:  '/home/rokety/dev/icicle/server.php'
/home/rokety/software/php-5.6.15/Zend/zend_vm_execute.h(944) :  Freeing 0x071F6418 (32 bytes), script=/home/rokety/dev/icicle/server.php
=== Total 1 memory leaks detected ===

If I pass false in Icicle\Loop\loop():

function loop(Loop $loop = null)
    {
        static $instance;

        if (null !== $loop) {
            $instance = $loop;
        } elseif (null === $instance) {
            $instance = create(false);
        }

        return $instance;
    }

zend engine doesn't complain the memory leak. So there is something wrong with the signal handling?

@bwoebi
Copy link

bwoebi commented Jan 25, 2016

Eventually try compiling php-src master branch which fixes a bunch of memory leaks.
There are leaks involving cleanup of Generators and Exceptions in older versions.

As long as these leaks aren't numerous, there's nothing you need to bother about. (After all, it's just 32 bytes ...)

@trowski
Copy link
Contributor

trowski commented Jan 25, 2016

@yangxikun What sort of high concurrency are you talking about? I've successfully tested a couple thousand concurrent requests with no issues. Does the server just hang (even with no load) after this happens? I'm going to need a little more information to track down what might be happening.

@yangxikun
Copy link
Author

Under high concurrency, the server script will hold many connections at the same time.
In my case, each request will make a remote request to another web services. It meant each request will cost a lot of time.
So, Increasingly connections that hold by server, will lead to more memory use, until the amount of memory use exceed php limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants