Skip to content

Commit 1173cc7

Browse files
committed
feature: added new config directive "lua_malloc_trim N" to periodically call malloc_trim(1) every N requests when malloc_trim() is available.
By default, "lua_malloc_trim 1000" is configured. This should fix the glibc oddity of holding too much freed memory when it fails to use brk() to allocate memory in the data segment.
1 parent 91fc078 commit 1173cc7

File tree

7 files changed

+502
-0
lines changed

7 files changed

+502
-0
lines changed

README.markdown

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,7 @@ Directives
10021002
==========
10031003

10041004
* [lua_use_default_type](#lua_use_default_type)
1005+
* [lua_malloc_trim](#lua_malloc_trim)
10051006
* [lua_code_cache](#lua_code_cache)
10061007
* [lua_regex_cache_max_entries](#lua_regex_cache_max_entries)
10071008
* [lua_regex_match_limit](#lua_regex_match_limit)
@@ -1089,6 +1090,31 @@ This directive was first introduced in the `v0.9.1` release.
10891090

10901091
[Back to TOC](#directives)
10911092

1093+
lua_malloc_trim
1094+
---------------
1095+
**syntax:** *lua_malloc_trim <request-count>*
1096+
1097+
**default:** *lua_malloc_trim 1000*
1098+
1099+
**context:** *http*
1100+
1101+
Asks the underlying `libc` runtime library to release its cached free memory back to the operating system every
1102+
`N` requests processed by the NGINX core. By default, `N` is 1000. You can configure the request count
1103+
by using your own numbers. Smaller numbers mean more frequent releases, which may introduce higher CPU time consumption and
1104+
smaller memory footprint while larger numbers usually lead to less CPU time overhead and relatively larger memory footprint.
1105+
Just tune the number for your own use cases.
1106+
1107+
Configuring the argument to `0` essentially turns off the periodical memory trimming altogether.
1108+
1109+
The current implementation uses an NGINX log phase handler to do the request counting. So the appearance of the
1110+
[log_subrequest on](http://nginx.org/en/docs/http/ngx_http_core_module.html#log_subrequest) directives in `nginx.conf`
1111+
may make the counting faster when subrequests are involved. By default, only "main requests" count.
1112+
1113+
Note that this directive does *not* affect the memory allocated by LuaJIT's own allocator based on the `mmap`
1114+
system call.
1115+
1116+
[Back to TOC](#directives)
1117+
10921118
lua_code_cache
10931119
--------------
10941120
**syntax:** *lua_code_cache on | off*

config

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,24 @@ CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS"
519519

520520
CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS"
521521

522+
# ----------------------------------------
523+
524+
ngx_feature="malloc_trim"
525+
ngx_feature_libs=
526+
ngx_feature_name="NGX_HTTP_LUA_HAVE_MALLOC_TRIM"
527+
ngx_feature_run=yes
528+
ngx_feature_incs="#include <malloc.h>
529+
#include <stdio.h>"
530+
ngx_feature_test="int rc = malloc_trim((size_t) 0); printf(\"%d\", rc);"
531+
SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS"
532+
CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS"
533+
534+
. auto/feature
535+
536+
CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS"
537+
538+
# ----------------------------------------
539+
522540
if test -n "$ngx_module_link"; then
523541
ngx_module_type=HTTP_AUX_FILTER
524542
ngx_module_name=$ngx_addon_name

doc/HttpLuaModule.wiki

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,32 @@ This directive is turned on by default.
840840
841841
This directive was first introduced in the <code>v0.9.1</code> release.
842842
843+
== lua_malloc_trim ==
844+
'''syntax:''' ''lua_malloc_trim <request-count>''
845+
846+
'''default:''' ''lua_malloc_trim 1000''
847+
848+
'''context:''' ''http''
849+
850+
Asks the underlying <code>libc</code> runtime library to release its cached free memory back to the operating system every
851+
<code>N</code> requests processed by the NGINX core. By default, <code>N</code> is 1000. You can configure the request count
852+
by using your own numbers. Smaller numbers mean more frequent releases, which may introduce higher CPU time consumption and
853+
smaller memory footprint while larger numbers usually lead to less CPU time overhead and relatively larger memory footprint.
854+
Just tune the number for your own use cases.
855+
856+
Configuring the argument to <code>0</code> essentially turns off the periodical memory trimming altogether.
857+
858+
<geshi lang="nginx">
859+
lua_malloc_trim 0; # turn off trimming completely
860+
</geshi>
861+
862+
The current implementation uses an NGINX log phase handler to do the request counting. So the appearance of the
863+
[http://nginx.org/en/docs/http/ngx_http_core_module.html#log_subrequest log_subrequest on] directives in <code>nginx.conf</code>
864+
may make the counting faster when subrequests are involved. By default, only "main requests" count.
865+
866+
Note that this directive does *not* affect the memory allocated by LuaJIT's own allocator based on the <code>mmap</code>
867+
system call.
868+
843869
== lua_code_cache ==
844870
'''syntax:''' ''lua_code_cache on | off''
845871

src/ngx_http_lua_common.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,10 @@ struct ngx_http_lua_main_conf_s {
193193

194194
ngx_http_lua_sema_mm_t *sema_mm;
195195

196+
ngx_uint_t malloc_trim_cycle; /* a cycle is defined as the number
197+
of reqeusts */
198+
ngx_uint_t malloc_trim_req_count;
199+
196200
unsigned requires_header_filter:1;
197201
unsigned requires_body_filter:1;
198202
unsigned requires_capture_filter:1;

src/ngx_http_lua_logby.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
#include "ngx_http_lua_shdict.h"
2828
#include "ngx_http_lua_util.h"
2929
#include "ngx_http_lua_exception.h"
30+
#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
31+
#include <malloc.h>
32+
#endif
3033

3134

3235
static ngx_int_t ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r);
@@ -67,9 +70,43 @@ ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r)
6770
ngx_int_t
6871
ngx_http_lua_log_handler(ngx_http_request_t *r)
6972
{
73+
#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
74+
ngx_uint_t trim_cycle, trim_nreq;
75+
ngx_http_lua_main_conf_t *lmcf;
76+
#endif
7077
ngx_http_lua_loc_conf_t *llcf;
7178
ngx_http_lua_ctx_t *ctx;
7279

80+
#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
81+
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
82+
83+
trim_cycle = lmcf->malloc_trim_cycle;
84+
85+
if (trim_cycle > 0) {
86+
87+
dd("cycle: %d", (int) trim_cycle);
88+
89+
trim_nreq = ++lmcf->malloc_trim_req_count;
90+
91+
if (trim_nreq >= trim_cycle) {
92+
lmcf->malloc_trim_req_count = 0;
93+
94+
#if (NGX_DEBUG)
95+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
96+
"malloc_trim(1) returned %d", malloc_trim(1));
97+
#else
98+
(void) malloc_trim(1);
99+
#endif
100+
}
101+
}
102+
# if (NGX_DEBUG)
103+
else {
104+
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
105+
"malloc_trim() disabled");
106+
}
107+
# endif
108+
#endif
109+
73110
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
74111
"lua log handler, uri:\"%V\" c:%ud", &r->uri,
75112
r->main->count);

src/ngx_http_lua_module.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ void ngx_http_lua_limit_data_segment(void);
5353
static ngx_int_t ngx_http_lua_pre_config(ngx_conf_t *cf);
5454
# endif
5555
#endif
56+
static char *ngx_http_lua_malloc_trim(ngx_conf_t *cf, ngx_command_t *cmd,
57+
void *conf);
5658

5759

5860
static ngx_conf_post_t ngx_http_lua_lowat_post =
@@ -578,6 +580,13 @@ static ngx_command_t ngx_http_lua_cmds[] = {
578580

579581
#endif /* NGX_HTTP_SSL */
580582

583+
{ ngx_string("lua_malloc_trim"),
584+
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
585+
ngx_http_lua_malloc_trim,
586+
NGX_HTTP_MAIN_CONF_OFFSET,
587+
0,
588+
NULL },
589+
581590
ngx_null_command
582591
};
583592

@@ -832,6 +841,10 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf)
832841
lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET;
833842
lmcf->postponed_to_access_phase_end = NGX_CONF_UNSET;
834843

844+
#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
845+
lmcf->malloc_trim_cycle = NGX_CONF_UNSET_UINT;
846+
#endif
847+
835848
#ifndef NGX_LUA_NO_FFI_API
836849
rc = ngx_http_lua_sema_mm_init(cf, lmcf);
837850
if (rc != NGX_OK) {
@@ -868,6 +881,12 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf)
868881
lmcf->max_running_timers = 256;
869882
}
870883

884+
#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
885+
if (lmcf->malloc_trim_cycle == NGX_CONF_UNSET_UINT) {
886+
lmcf->malloc_trim_cycle = 1000; /* number of reqs */
887+
}
888+
#endif
889+
871890
lmcf->cycle = cf->cycle;
872891

873892
return NGX_CONF_OK;
@@ -1283,4 +1302,39 @@ ngx_http_lua_limit_data_segment(void)
12831302
}
12841303
#endif
12851304

1305+
1306+
static char *
1307+
ngx_http_lua_malloc_trim(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1308+
{
1309+
#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
1310+
1311+
ngx_int_t nreqs;
1312+
ngx_str_t *value;
1313+
1314+
ngx_http_lua_main_conf_t *lmcf = conf;
1315+
1316+
value = cf->args->elts;
1317+
1318+
nreqs = ngx_atoi(value[1].data, value[1].len);
1319+
if (nreqs == NGX_ERROR) {
1320+
return "invalid number in the 1st argument";
1321+
}
1322+
1323+
lmcf->malloc_trim_cycle = (ngx_uint_t) nreqs;
1324+
1325+
if (nreqs == 0) {
1326+
return NGX_CONF_OK;
1327+
}
1328+
1329+
lmcf->requires_log = 1;
1330+
1331+
#else
1332+
1333+
ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "lua_malloc_trim is not supported "
1334+
"on this platform, ignored");
1335+
1336+
#endif
1337+
return NGX_CONF_OK;
1338+
}
1339+
12861340
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */

0 commit comments

Comments
 (0)