php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #29560 Listening on non-blocking socket leaks memory
Submitted: 2004-08-07 03:01 UTC Modified: 2004-09-28 10:00 UTC
From: info at tphnet dot com Assigned:
Status: Closed Package: Sockets related
PHP Version: 5.0.0 OS: Windows XP SP1
Private report: No CVE-ID: None
 [2004-08-07 03:01 UTC] info at tphnet dot com
Description:
------------
I've been trying to write a simple multi-client server application in PHP. Everything is working just fine, the only problem is that the server is leaking memory.

Reproduce code:
---------------
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
		
socket_bind($socket, 'localhost', 1234);
socket_listen($socket);
socket_set_nonblock($socket);
		
while(true){
	
	$new_connection = @socket_accept($socket);
	unset($new_connection);
}

Expected result:
----------------
The above server will accept connections on localhot:1234 and will disconnect you directly after you connect.
The socket is setup in non-blocking mode, so that with a couple of minor modifications it becomes possible to handle multiple clients at the same time.


Actual result:
--------------
The code does exactly what it is supposed to do, but its memory use increases very fast. It fills up my 512 megs in about a minute.

The memory leak occours in the socket_accept() function. Removing this line will stop the memory leak from occouring. 
If you remove the socket_set_nonblock() function it also does not leak memory anymore. This seems kind of logical because the script will "hang" on the socket_accept() function instead of looping over it constantly.

In the version of the script I'm actually using, a "usleep(100000)" has been added in the while loop to make sure the script doesn't consume all available resources, but the memory leak still remains. Although it takes much longer to fill all memory because socket_accept() is called less frequent.

Removing the "@" sign infront of the socket_accept() function causes the following two errors to be printed on the console for every call to socket_accpet():

Warning: socket_accept(): unable to accept incoming connection [0]: Een niet-blokkerende socketbewerking kan niet onmiddellijk worden voltooid.
Warning: socket_accept(): unable to accept socket connection [0]: De bewerking is voltooid.

The first error roughly translates to "A non-blocking socket action cannot be executed immediately" and the second to "The action has been completed".

I'm not really an expert on sockets so I'm not sure if my script is just flawed or this is a real bug. I've used the above code in a somewhat more advanced form to create a small POP3 server. This server is functioning just fine, the only problem is that it is leaking memory.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2004-08-07 14:50 UTC] wez@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php5-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php5-win32-latest.zip
 [2004-08-07 15:07 UTC] wez@php.net
Urgh, ignore that (clicked wrong link).
The sockets extension is unmaintained.
Try stream_socket_create() and fiends instead.
 [2004-08-07 17:55 UTC] info at tphnet dot com
I changed to code to the following:

<?php

$socket = stream_socket_server('tcp://localhost:1234', $errno, $errstr);
stream_set_blocking($socket, 0);

	while(true){
			
		$new_connection = @stream_socket_accept($socket, 0);
			
		unset($new_connection);}

?>

There is no memory leak anymore and everything is working as expected. It appears the problem is solved.
 [2004-08-07 19:23 UTC] info at tphnet dot com
I can confirm the memory leak that I described in my original bug report has disappeard.

BUT, I found a new memory leak inside the stream_socket_accept() function. If you set the third argument peername to a variable, the function will leak a little bit of memory everytime it's called. The effect is the same as with the original bug in socket_accpet().
Just modify the example in my previous reply by changing

$new_connection = @stream_socket_accept($socket, 0);

into

$new_connection = @stream_socket_accept($socket, 0, $peer);

and see what happens. In my case (Windows XP, php 5.0.0 CLI) the script starts leaking memory.
 [2004-08-08 01:47 UTC] wez@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php5-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php5-win32-latest.zip

Try a snapshot, as a couple of peername related bugs were fixed recently.
 [2004-08-09 02:04 UTC] info at tphnet dot com
Tested using:

PHP 5.1.0-dev (cli) (built: Aug  8 2004 16:31:06)

The memory leak is still there, as described in my previous reply.
 [2004-09-18 01:49 UTC] master_tip at hotmail dot com
hi i'm docey,

i'm also writing a cli app that used a multi-client socket functions. at first i was using the deprecated socket functions and indeed found a memory leak. so i started re-writing my socket functions to use the almost similair stream functions. my aim was a simple interface in the some how complicated socket programming stuff. but i think i found a new part on this memory leak. 

the script is running cli on windows2000sp4 with php5.01(latest) and all works fine i can even have a short chat with myself using two telnet windows and then it happens. when i close the first telnet window php start eating memory rapidly and within a minute it grows from 6mb to 11mb but when i close the second telnet window it stops eating memory. the script is running quite a lot of loops per minute about 30000 i guese so there be a lot of socket_accepts and stream_switch when there is nothing else to do. 

the script is programmed to select a random function from a predefined list if there is no other function to be run. so a lot of checks are done. could it be something in the way telnet closed a connection. i'm using the standard telnet client in the windows2000 prompt. or is there a problem with stream_switch. i have checked if the script is not storing variables as an idiot in the arrays because that would eat a lot of memory too. 

also i haven't checked it with more then 2 clients running. and now i'm thinking when a client rapidly departs and php could not unset the socket form the list yet, and stream_switch would run over the sockets gathering new info. maybe stream_switch would be causing this because it sees an dead connection and can't handle with it. 

anyway, this is my story to the socket memory leak. if any of you have any ideas whats causing these leaks. i'm not the only one who's pleased to hear it(i hope, my c++ is not that good anymore). 

docey, the netherlands.

ps. sorry for my broken english.
 [2004-09-18 18:19 UTC] wez@php.net
Please try using this CVS snapshot:

  http://snaps.php.net/php5-latest.tar.gz
 
For Windows:
 
  http://snaps.php.net/win32/php5-win32-latest.zip


 [2004-09-27 01:00 UTC] php-bugs at lists dot php dot net
No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
 [2004-09-28 10:00 UTC] wez@php.net
Considered fixed in 5.1
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 25 16:01:28 2024 UTC