Memory leaks when used as a shared library

Hi,

I want to build nginx into a shared library for this feature of
nginx-clojure: APIs for Embedding Nginx-Clojure into a Clojure/Java/Groovy App · Issue #86 · nginx-clojure/nginx-clojure · GitHub
.
But i found that there’s memory leaks after stop server but without exit
the
process. Then I tried valgrind to check a simple test without any 3rd
party
module.

$ nginx -V

nginx version: nginx/1.8.0
built by gcc 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
configure arguments:
$

test.conf
=================start of test.conf==============================

daemon off;
master_process off;

error_log logs/error.log;

events {
worker_connections 1024;
}

http {

include       mime.types;
default_type  text/html;

access_log off;

sendfile        on;

keepalive_timeout  65;

server {
   listen       8081;
   server_name  localhost;

   location /hello {
      alias /nginx-clojure-embed/test/work-dir;
   }
}

}

=================end of test.conf==============================

The result of valgrind is here:

$ valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all
–leak-check=yes objs/nginx -c work-dir/test.conf -p work-dir
==10039== Memcheck, a memory error detector
==10039== Copyright (C) 2002-2013, and GNU GPL’d, by Julian Seward et
al.
==10039== Using Valgrind-3.11.0.SVN and LibVEX; rerun with -h for
copyright
info
==10039== Command: objs/nginx -c work-dir/test.conf -p work-dir
==10039==
-==10039==
==10039== HEAP SUMMARY:
==10039== in use at exit: 441,239 bytes in 148 blocks
==10039== total heap usage: 197 allocs, 49 frees, 613,884 bytes
allocated
==10039==
==10039== 48 bytes in 1 blocks are still reachable in loss record 1 of
10
==10039== at 0x4C2ABFD: malloc (vg_replace_malloc.c:299)
==10039== by 0x41CB98: ngx_alloc (ngx_alloc.c:22)
==10039== by 0x403E9B: ngx_save_argv (nginx.c:817)
==10039== by 0x40434D: main (nginx.c:316)
==10039==
==10039== 128 bytes in 1 blocks are possibly lost in loss record 2 of 10
==10039== at 0x4C2ABFD: malloc (vg_replace_malloc.c:299)
==10039== by 0x41CB98: ngx_alloc (ngx_alloc.c:22)
==10039== by 0x40CAD2: ngx_crc32_table_init (ngx_crc32.c:117)
==10039== by 0x40452C: main (nginx.c:332)
==10039==
==10039== 151 bytes in 5 blocks are still reachable in loss record 3 of
10
==10039== at 0x4C2ABFD: malloc (vg_replace_malloc.c:299)
==10039== by 0x41CB98: ngx_alloc (ngx_alloc.c:22)
==10039== by 0x403EE7: ngx_save_argv (nginx.c:825)
==10039== by 0x40434D: main (nginx.c:316)
==10039==
==10039== 2,160 bytes in 1 blocks are still reachable in loss record 4
of
10
==10039== at 0x4C2ABFD: malloc (vg_replace_malloc.c:299)
==10039== by 0x41CACD: ngx_strerror_init (ngx_errno.c:60)
==10039== by 0x403F74: main (nginx.c:211)
==10039==
==10039== 3,030 bytes in 135 blocks are still reachable in loss record 5
of
10
==10039== at 0x4C2ABFD: malloc (vg_replace_malloc.c:299)
==10039== by 0x41CB0E: ngx_strerror_init (ngx_errno.c:69)
==10039== by 0x403F74: main (nginx.c:211)
==10039==
==10039== 3,594 bytes in 1 blocks are still reachable in loss record 6
of
10
==10039== at 0x4C2ABFD: malloc (vg_replace_malloc.c:299)
==10039== by 0x41CB98: ngx_alloc (ngx_alloc.c:22)
==10039== by 0x41F260: ngx_init_setproctitle (ngx_setproctitle.c:47)
==10039== by 0x41F3E4: ngx_os_init (ngx_posix_init.c:43)
==10039== by 0x4048F4: main (nginx.c:324)
==10039==
==10039== 6,144 bytes in 1 blocks are still reachable in loss record 7
of
10
==10039== at 0x4C2ABFD: malloc (vg_replace_malloc.c:299)
==10039== by 0x41CB98: ngx_alloc (ngx_alloc.c:22)
==10039== by 0x421832: ngx_epoll_init (ngx_epoll_module.c:348)
==10039== by 0x41A239: ngx_event_process_init (ngx_event.c:626)
==10039== by 0x42132C: ngx_single_process_cycle
(ngx_process_cycle.c:298)
==10039== by 0x4048A7: main (nginx.c:416)
==10039==
==10039== 106,496 bytes in 1 blocks are indirectly lost in loss record 8
of
10
==10039== at 0x4C2ABFD: malloc (vg_replace_malloc.c:299)
==10039== by 0x41CB98: ngx_alloc (ngx_alloc.c:22)
==10039== by 0x41A424: ngx_event_process_init (ngx_event.c:689)
==10039== by 0x42132C: ngx_single_process_cycle
(ngx_process_cycle.c:298)
==10039== by 0x4048A7: main (nginx.c:416)
==10039==
==10039== 106,496 bytes in 1 blocks are indirectly lost in loss record 9
of
10
==10039== at 0x4C2ABFD: malloc (vg_replace_malloc.c:299)
==10039== by 0x41CB98: ngx_alloc (ngx_alloc.c:22)
==10039== by 0x41A479: ngx_event_process_init (ngx_event.c:701)
==10039== by 0x42132C: ngx_single_process_cycle
(ngx_process_cycle.c:298)
==10039== by 0x4048A7: main (nginx.c:416)
==10039==
==10039== 425,984 (212,992 direct, 212,992 indirect) bytes in 1 blocks
are
definitely lost in loss record 10 of 10
==10039== at 0x4C2ABFD: malloc (vg_replace_malloc.c:299)
==10039== by 0x41CB98: ngx_alloc (ngx_alloc.c:22)
==10039== by 0x41A3F5: ngx_event_process_init (ngx_event.c:682)
==10039== by 0x42132C: ngx_single_process_cycle
(ngx_process_cycle.c:298)
==10039== by 0x4048A7: main (nginx.c:416)
==10039==
==10039== LEAK SUMMARY:
==10039== definitely lost: 212,992 bytes in 1 blocks
==10039== indirectly lost: 212,992 bytes in 2 blocks
==10039== possibly lost: 128 bytes in 1 blocks
==10039== still reachable: 15,127 bytes in 144 blocks
==10039== suppressed: 0 bytes in 0 blocks
==10039==
==10039== For counts of detected and suppressed errors, rerun with: -v
==10039== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

There are a lot of memory leaks. e.g. ngx_epoll_done will never be
called
so event_list has no chance to be freed.

Thanks.
Xfeep

Posted at Nginx Forum:

BTW, after start nginx by valgrind it won’t print memory leaks report
until
we stop nginx by

$ objs/nginx -c work-dir/test.conf -p work-dir

Posted at Nginx Forum:

Hello!

On Fri, Jul 31, 2015 at 09:57:05PM -0400, xfeep wrote:

I want to build nginx into a shared library for this feature of
nginx-clojure: APIs for Embedding Nginx-Clojure into a Clojure/Java/Groovy App · Issue #86 · nginx-clojure/nginx-clojure · GitHub .
But i found that there’s memory leaks after stop server but without exit the
process. Then I tried valgrind to check a simple test without any 3rd party
module.

Well, the answer is simple: nginx is not designed to be a shared
library. If you want to convert it to be one, it’s you who are
responsible for cleaning up various global allocations.


Maxim D.
http://nginx.org/

Hi, Maxim,

Thanks for your reply!

Well, the answer is simple: nginx is not designed to be a shared
library. If you want to convert it to be one, it’s you who are
responsible for cleaning up various global allocations.

You’re right.
But for module developers who use valgrind there are maybe some
confusion,
the built-in core modules also have “memory leaks” , despite the fact
that
those are not real leaks because OS will free them after nginx
master/worker processes exit.

Regards.
Xfeep

Posted at Nginx Forum:

Hi, Lord,
Thank you!

Lord N. Wrote:

Have you looked at GitHub - openresty/no-pool-nginx: replace nginx's pool mechanism with plain malloc & free to help tools like valgrind ?

But the issue in my case is not related to nginx’s pool mechanism.
It is caused by some build-in modules which won’t release it allocated
memory at all. e.g.
ngx_event_core_module.init_process does some allocating but there 's no
ngx_event_core_module.exit_process at all, so the memory it allocated
will
only be released by operation system process manager only when the
worker
process exits. it is plain that this will be reported as memory leak by
valgrind.

Just as Maxim said, I plan to write a new process_cycle for my shared
library and record all unreleased memory and do release them at the end
of
process_cycle.

Regards.
Xfeep

Posted at Nginx Forum:

Have you looked at GitHub - openresty/no-pool-nginx: replace nginx's pool mechanism with plain malloc & free to help tools like valgrind ?