lighttpd forum lighty > Memory leak?

Posted by Floris Bos
on 12.09.2006 00:53
I am using lighttpd 1.4.11 in a low-traffic virtual hosting setup and am
having the problem that it seems to consume large amounts of memory and
starts filling swap space after running for a day:

--
max@mx2:~> ps aux |grep lighttpd
www      13612  0.0 46.5 1176388 476588 ?      S    Sep10   1:25
/usr/local/sbin/lighttpd -f ./lighttpd.conf

Server-Status
Uptime	1 days 9 hours 25 min 18 s
Started at	2006-09-10 16:45:45
absolute (since start)
Requests	69 kreq
Traffic	1.12 Gbyte
average (since start)
Requests	0 req/s
Traffic	9.72 kbyte/s
average (5s sliding average)
Requests	1 req/s
Traffic	7.13 kbyte/s

5 connections
rrhrr

lighttpd 1.4.11
Server-Features
RegEx Conditionals 	enabled
Network Engine
fd-Event-Handler 	linux-sysepoll
Config-File-Settings
Loaded Modules 	indexfile
access
status
fastcgi
simple_vhost
cgi
compress
accesslog
evasive
dirlisting
staticfile
--

The strange thing is that I also run lighty on a different server for a
high-traffic website, yet it does not seem to have this problem.


===
max@lion:~> ps aux |grep lighttpd
nobody   11822  1.0  7.8 175880 156164 ?       S    Aug05 586:59
/usr/local/sbin/lighttpd -f lighttpd.conf

Server-Status
Uptime	37 days 3 hours 41 min 9 s
Started at	2006-08-05 22:47:08
absolute (since start)
Requests	63 Mreq
Traffic	696.10 Gbyte
average (since start)
Requests	19 req/s
Traffic	227.38 kbyte/s
average (5s sliding average)
Requests	13 req/s
Traffic	67.49 kbyte/s

48 connections
hhhhrhhrrrrrrrrrrrrrrrrhrrrrrrrrrrrrWrrrrrrrrrWh
===


The difference in configuration is that the first setup uses
mod_simple_vhost and runs PHP through CGI instead of FastCGI.
Are there any known memory leaks or other problems with these modules?
Posted by Peter Zaitsev (Guest)
on 14.10.2006 19:02
Floris Bos wrote:
> I am using lighttpd 1.4.11 in a low-traffic virtual hosting setup and am
> having the problem that it seems to consume large amounts of memory and
> starts filling swap space after running for a day:
> 
> --
> max@mx2:~> ps aux |grep lighttpd
> www      13612  0.0 46.5 1176388 476588 ?      S    Sep10   1:25
> /usr/local/sbin/lighttpd -f ./lighttpd.conf

Which OS and PHP version are you using.

I have same problem on CentOS with PHP 5.1.6  but it works well on 
Fedora Core 4.
It also works if I use PHP 5.1.2

So there are possibly some issues with new PHP Fast-CGI Interface, which 
are also platform specific :(
Posted by Floris Bos
on 28.10.2006 17:12
Peter Zaitsev wrote:
> Which OS and PHP version are you using.

Have these issues with both Suse and Ubuntu. PHP 5.1.6


I think I have found a possible cause.
Lighty seems to buffer the output of scripts indefinitely.

This means that if one of your users has a php script without proper
error handling among the lines of:

<?
...
while ( !feof($non_existing_fd)  )
{
  ...
}
?>

causing an endless loop outputting "Warning: feof(): supplied argument
is not a valid stream resource" until the execution times out, your
memory will be filled fast.

It seems that this buffer memory is NOT freed, or the memory is not 
properly returned to the OS, even after all client
connections to the server have been closed:

root@Host5:/home/max/etc# netstat -anp |grep lightt
tcp        0      0 0.0.0.0:80              0.0.0.0:*
LISTEN     5604/lighttpd
root@Host5:/home/max/etc# ps aux |grep lightt
root      5604 15.7 16.5 690080 688976 ?       S    00:28   1:30
/usr/local/sbin/lighttpd -f ./lighttpd.conf
Posted by Floris Bos
on 02.11.2006 03:51
Ok, figured it out.

Lighttpd does free the memory, but it is never returned to the Operating
system.

In the above situation in which PHP is in an endless loop, lighty seems
to do millions of very small memory allocations (chunks in the
con->write_queue) to buffer the output.
Small memory allocations are placed in a heap by glibc's memory
allocation routines.
Because the top of this heap is fragmented, it cannot return this memory
to the operating system when it is freed. Instead it is placed in a free
list, for reuse by the application.

Large memory allocations above 256 KB in size, are not placed in this
heap but in a seperate (mmap) memory region, and do get returned to the
operating system when they are freed.

I modified chunk.c a bit, so that it combines small chunks into chunks 
+/- 512 KB in size:

---
int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
	chunk *c;

	if (mem->used == 0) return 0;

	if (!cq->unused && cq->last && cq->last->type == MEM_CHUNK &&
cq->last->offset == 0 && cq->last->mem->used < 524288)
	{
		buffer_append_string_buffer(cq->last->mem, mem);
	}
	else
	{
		c = chunkqueue_get_unused_chunk(cq);
		c->type = MEM_CHUNK;
		c->offset = 0;
		buffer_copy_string_buffer(c->mem, mem);

		chunkqueue_append_chunk(cq, c);
	}

	return 0;
}

int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len)
{
	chunk *c;

	if (len == 0) return 0;

	if (!cq->unused && cq->last && cq->last->type == MEM_CHUNK &&
cq->last->offset == 0 && cq->last->mem->used < 524288)
	{
		buffer_append_string_len(cq->last->mem, mem, len-1);
	}
	else
	{
		c = chunkqueue_get_unused_chunk(cq);
		c->type = MEM_CHUNK;
		c->offset = 0;
		buffer_copy_string_len(c->mem, mem, len - 1);

		chunkqueue_append_chunk(cq, c);
	}

	return 0;
}
---

Now lighty still consumes a lot of memory DURING the execution of a
broken php script:

# ps aux |grep lighttpd
root     14439  4.3  9.0 375824 374780 ?       S    09:52   1:13
/usr/local/sbin/lighttpd -f ./lighttpd.conf

But afterwards it does return the memory to the OS:

# ps aux |grep lighttpd
root     14439  4.1  0.0   2324  1280 ?        S    09:52   1:13
/usr/local/sbin/lighttpd -f ./lighttpd.conf


That seems a lot better.
However during the execution of the script, memory usage is still high
and therefore there is a risk that the OS starts swapping or kills
lighty.
There should really be an option to limit the amount of data that is
buffered in the first place.