Permalink
Browse files

feature: added new config directive "lua_malloc_trim N" to periodical…

…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...
1 parent 91fc078 commit 1173cc7c936b797782ad03bc3cb8b3b6761c6fce @agentzh agentzh committed Oct 2, 2016
Showing with 502 additions and 0 deletions.
  1. +26 −0 README.markdown
  2. +18 −0 config
  3. +26 −0 doc/HttpLuaModule.wiki
  4. +4 −0 src/ngx_http_lua_common.h
  5. +37 −0 src/ngx_http_lua_logby.c
  6. +54 −0 src/ngx_http_lua_module.c
  7. +337 −0 t/146-malloc-trim.t
View
@@ -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)
@@ -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*
View
@@ -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
@@ -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''
@@ -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;
@@ -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);
@@ -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);
@@ -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 =
@@ -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
};
@@ -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) {
@@ -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;
@@ -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: */
Oops, something went wrong.

0 comments on commit 1173cc7

Please sign in to comment.