Skip to content

Commit

Permalink
feature: added new config directive "lua_malloc_trim N" to periodical…
Browse files Browse the repository at this point in the history
…ly 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.
  • Loading branch information
agentzh committed Oct 23, 2016
1 parent 91fc078 commit 1173cc7
Show file tree
Hide file tree
Showing 7 changed files with 502 additions and 0 deletions.
26 changes: 26 additions & 0 deletions README.markdown
Expand Up @@ -1002,6 +1002,7 @@ Directives
==========

* [lua_use_default_type](#lua_use_default_type)
* [lua_malloc_trim](#lua_malloc_trim)
* [lua_code_cache](#lua_code_cache)
* [lua_regex_cache_max_entries](#lua_regex_cache_max_entries)
* [lua_regex_match_limit](#lua_regex_match_limit)
Expand Down Expand Up @@ -1089,6 +1090,31 @@ This directive was first introduced in the `v0.9.1` release.

[Back to TOC](#directives)

lua_malloc_trim
---------------
**syntax:** *lua_malloc_trim <request-count>*

**default:** *lua_malloc_trim 1000*

**context:** *http*

Asks the underlying `libc` runtime library to release its cached free memory back to the operating system every
`N` requests processed by the NGINX core. By default, `N` is 1000. You can configure the request count
by using your own numbers. Smaller numbers mean more frequent releases, which may introduce higher CPU time consumption and
smaller memory footprint while larger numbers usually lead to less CPU time overhead and relatively larger memory footprint.
Just tune the number for your own use cases.

Configuring the argument to `0` essentially turns off the periodical memory trimming altogether.

The current implementation uses an NGINX log phase handler to do the request counting. So the appearance of the
[log_subrequest on](http://nginx.org/en/docs/http/ngx_http_core_module.html#log_subrequest) directives in `nginx.conf`
may make the counting faster when subrequests are involved. By default, only "main requests" count.

Note that this directive does *not* affect the memory allocated by LuaJIT's own allocator based on the `mmap`
system call.

[Back to TOC](#directives)

lua_code_cache
--------------
**syntax:** *lua_code_cache on | off*
Expand Down
18 changes: 18 additions & 0 deletions config
Expand Up @@ -519,6 +519,24 @@ CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS"

CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS"

# ----------------------------------------

ngx_feature="malloc_trim"
ngx_feature_libs=
ngx_feature_name="NGX_HTTP_LUA_HAVE_MALLOC_TRIM"
ngx_feature_run=yes
ngx_feature_incs="#include <malloc.h>
#include <stdio.h>"
ngx_feature_test="int rc = malloc_trim((size_t) 0); printf(\"%d\", rc);"
SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS"
CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS"

. auto/feature

CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS"

# ----------------------------------------

if test -n "$ngx_module_link"; then
ngx_module_type=HTTP_AUX_FILTER
ngx_module_name=$ngx_addon_name
Expand Down
26 changes: 26 additions & 0 deletions doc/HttpLuaModule.wiki
Expand Up @@ -840,6 +840,32 @@ This directive is turned on by default.
This directive was first introduced in the <code>v0.9.1</code> release.
== lua_malloc_trim ==
'''syntax:''' ''lua_malloc_trim <request-count>''
'''default:''' ''lua_malloc_trim 1000''
'''context:''' ''http''
Asks the underlying <code>libc</code> runtime library to release its cached free memory back to the operating system every
<code>N</code> requests processed by the NGINX core. By default, <code>N</code> is 1000. You can configure the request count
by using your own numbers. Smaller numbers mean more frequent releases, which may introduce higher CPU time consumption and
smaller memory footprint while larger numbers usually lead to less CPU time overhead and relatively larger memory footprint.
Just tune the number for your own use cases.
Configuring the argument to <code>0</code> essentially turns off the periodical memory trimming altogether.
<geshi lang="nginx">
lua_malloc_trim 0; # turn off trimming completely
</geshi>
The current implementation uses an NGINX log phase handler to do the request counting. So the appearance of the
[http://nginx.org/en/docs/http/ngx_http_core_module.html#log_subrequest log_subrequest on] directives in <code>nginx.conf</code>
may make the counting faster when subrequests are involved. By default, only "main requests" count.
Note that this directive does *not* affect the memory allocated by LuaJIT's own allocator based on the <code>mmap</code>
system call.
== lua_code_cache ==
'''syntax:''' ''lua_code_cache on | off''
Expand Down
4 changes: 4 additions & 0 deletions src/ngx_http_lua_common.h
Expand Up @@ -193,6 +193,10 @@ struct ngx_http_lua_main_conf_s {

ngx_http_lua_sema_mm_t *sema_mm;

ngx_uint_t malloc_trim_cycle; /* a cycle is defined as the number
of reqeusts */
ngx_uint_t malloc_trim_req_count;

unsigned requires_header_filter:1;
unsigned requires_body_filter:1;
unsigned requires_capture_filter:1;
Expand Down
37 changes: 37 additions & 0 deletions src/ngx_http_lua_logby.c
Expand Up @@ -27,6 +27,9 @@
#include "ngx_http_lua_shdict.h"
#include "ngx_http_lua_util.h"
#include "ngx_http_lua_exception.h"
#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
#include <malloc.h>
#endif


static ngx_int_t ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r);
Expand Down Expand Up @@ -67,9 +70,43 @@ ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r)
ngx_int_t
ngx_http_lua_log_handler(ngx_http_request_t *r)
{
#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
ngx_uint_t trim_cycle, trim_nreq;
ngx_http_lua_main_conf_t *lmcf;
#endif
ngx_http_lua_loc_conf_t *llcf;
ngx_http_lua_ctx_t *ctx;

#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);

trim_cycle = lmcf->malloc_trim_cycle;

if (trim_cycle > 0) {

dd("cycle: %d", (int) trim_cycle);

trim_nreq = ++lmcf->malloc_trim_req_count;

if (trim_nreq >= trim_cycle) {
lmcf->malloc_trim_req_count = 0;

#if (NGX_DEBUG)
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"malloc_trim(1) returned %d", malloc_trim(1));
#else
(void) malloc_trim(1);
#endif
}
}
# if (NGX_DEBUG)
else {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"malloc_trim() disabled");
}
# endif
#endif

ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"lua log handler, uri:\"%V\" c:%ud", &r->uri,
r->main->count);
Expand Down
54 changes: 54 additions & 0 deletions src/ngx_http_lua_module.c
Expand Up @@ -53,6 +53,8 @@ void ngx_http_lua_limit_data_segment(void);
static ngx_int_t ngx_http_lua_pre_config(ngx_conf_t *cf);
# endif
#endif
static char *ngx_http_lua_malloc_trim(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);


static ngx_conf_post_t ngx_http_lua_lowat_post =
Expand Down Expand Up @@ -578,6 +580,13 @@ static ngx_command_t ngx_http_lua_cmds[] = {

#endif /* NGX_HTTP_SSL */

{ ngx_string("lua_malloc_trim"),
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
ngx_http_lua_malloc_trim,
NGX_HTTP_MAIN_CONF_OFFSET,
0,
NULL },

ngx_null_command
};

Expand Down Expand Up @@ -832,6 +841,10 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf)
lmcf->postponed_to_rewrite_phase_end = NGX_CONF_UNSET;
lmcf->postponed_to_access_phase_end = NGX_CONF_UNSET;

#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
lmcf->malloc_trim_cycle = NGX_CONF_UNSET_UINT;
#endif

#ifndef NGX_LUA_NO_FFI_API
rc = ngx_http_lua_sema_mm_init(cf, lmcf);
if (rc != NGX_OK) {
Expand Down Expand Up @@ -868,6 +881,12 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf)
lmcf->max_running_timers = 256;
}

#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
if (lmcf->malloc_trim_cycle == NGX_CONF_UNSET_UINT) {
lmcf->malloc_trim_cycle = 1000; /* number of reqs */
}
#endif

lmcf->cycle = cf->cycle;

return NGX_CONF_OK;
Expand Down Expand Up @@ -1283,4 +1302,39 @@ ngx_http_lua_limit_data_segment(void)
}
#endif


static char *
ngx_http_lua_malloc_trim(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)

ngx_int_t nreqs;
ngx_str_t *value;

ngx_http_lua_main_conf_t *lmcf = conf;

value = cf->args->elts;

nreqs = ngx_atoi(value[1].data, value[1].len);
if (nreqs == NGX_ERROR) {
return "invalid number in the 1st argument";
}

lmcf->malloc_trim_cycle = (ngx_uint_t) nreqs;

if (nreqs == 0) {
return NGX_CONF_OK;
}

lmcf->requires_log = 1;

#else

ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "lua_malloc_trim is not supported "
"on this platform, ignored");

#endif
return NGX_CONF_OK;
}

/* vi:set ft=c ts=4 sw=4 et fdm=marker: */

0 comments on commit 1173cc7

Please sign in to comment.