[njs] QuickJS: added memory limit check for reuse queue.
noreply at nginx.com
noreply at nginx.com
Tue May 27 22:21:02 UTC 2025
details: https://github.com/nginx/njs/commit/0c0d4e50ec4d582b345bc64c12b737b109b7bc03
branches: master
commit: 0c0d4e50ec4d582b345bc64c12b737b109b7bc03
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Wed, 21 May 2025 17:10:15 -0700
description:
QuickJS: added memory limit check for reuse queue.
---
nginx/ngx_http_js_module.c | 7 +++++++
nginx/ngx_js.c | 26 ++++++++++++++++++++++++++
nginx/ngx_js.h | 1 +
nginx/ngx_stream_js_module.c | 7 +++++++
4 files changed, 41 insertions(+)
diff --git a/nginx/ngx_http_js_module.c b/nginx/ngx_http_js_module.c
index 28798172..1e0a927f 100644
--- a/nginx/ngx_http_js_module.c
+++ b/nginx/ngx_http_js_module.c
@@ -433,6 +433,13 @@ static ngx_command_t ngx_http_js_commands[] = {
offsetof(ngx_http_js_loc_conf_t, reuse),
NULL },
+ { ngx_string("js_context_reuse_max_size"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_js_loc_conf_t, reuse_max_size),
+ NULL },
+
{ ngx_string("js_import"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13,
ngx_js_import,
diff --git a/nginx/ngx_js.c b/nginx/ngx_js.c
index e4bae32a..515218b9 100644
--- a/nginx/ngx_js.c
+++ b/nginx/ngx_js.c
@@ -1133,6 +1133,7 @@ ngx_engine_qjs_destroy(ngx_engine_t *e, ngx_js_ctx_t *ctx,
JSRuntime *rt;
JSContext *cx;
JSClassID class_id;
+ JSMemoryUsage stats;
ngx_qjs_event_t *event;
ngx_js_opaque_t *opaque;
njs_rbtree_node_t *node;
@@ -1198,6 +1199,28 @@ ngx_engine_qjs_destroy(ngx_engine_t *e, ngx_js_ctx_t *ctx,
cln->data = conf->reuse_queue;
}
+ /*
+ * After the request object is freed, the runtime's memory usage should
+ * be low. It can only remain high if the global scope was
+ * modified.
+ *
+ * To prevent unlimited memory consumption growth, check whether memory
+ * usage exceeds the configured limit. The check is performed rarely to
+ * avoid performance impact of JS_ComputeMemoryUsage() which is slow.
+ */
+
+ if ((ngx_random() & 0xff) == 1) {
+ JS_ComputeMemoryUsage(JS_GetRuntime(cx), &stats);
+
+ if ((size_t) stats.malloc_size > conf->reuse_max_size) {
+ ngx_log_error(NGX_LOG_WARN, ctx->log, 0,
+ "js remaining memory usage of the context "
+ "exceeds \"js_context_reuse_max_size\" limit: %L"
+ ", not reusing it", stats.malloc_size);
+ goto free_ctx;
+ }
+ }
+
if (ngx_js_queue_push(conf->reuse_queue, cx) != NGX_OK) {
goto free_ctx;
}
@@ -3950,6 +3973,7 @@ ngx_js_create_conf(ngx_conf_t *cf, size_t size)
conf->preload_objects = NGX_CONF_UNSET_PTR;
conf->reuse = NGX_CONF_UNSET_SIZE;
+ conf->reuse_max_size = NGX_CONF_UNSET_SIZE;
conf->buffer_size = NGX_CONF_UNSET_SIZE;
conf->max_response_body_size = NGX_CONF_UNSET_SIZE;
conf->timeout = NGX_CONF_UNSET_MSEC;
@@ -4059,6 +4083,8 @@ ngx_js_merge_conf(ngx_conf_t *cf, void *parent, void *child,
ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
ngx_conf_merge_size_value(conf->reuse, prev->reuse, 128);
+ ngx_conf_merge_size_value(conf->reuse_max_size, prev->reuse_max_size,
+ 4 * 1024 * 1024);
ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 16384);
ngx_conf_merge_size_value(conf->max_response_body_size,
prev->max_response_body_size, 1048576);
diff --git a/nginx/ngx_js.h b/nginx/ngx_js.h
index 122881af..99330f88 100644
--- a/nginx/ngx_js.h
+++ b/nginx/ngx_js.h
@@ -122,6 +122,7 @@ typedef struct {
ngx_uint_t type; \
ngx_engine_t *engine; \
ngx_uint_t reuse; \
+ size_t reuse_max_size; \
ngx_js_queue_t *reuse_queue; \
ngx_str_t cwd; \
ngx_array_t *imports; \
diff --git a/nginx/ngx_stream_js_module.c b/nginx/ngx_stream_js_module.c
index fb58cdc6..328ce581 100644
--- a/nginx/ngx_stream_js_module.c
+++ b/nginx/ngx_stream_js_module.c
@@ -264,6 +264,13 @@ static ngx_command_t ngx_stream_js_commands[] = {
offsetof(ngx_stream_js_srv_conf_t, reuse),
NULL },
+ { ngx_string("js_context_reuse_max_size"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ offsetof(ngx_stream_js_srv_conf_t, reuse_max_size),
+ NULL },
+
{ ngx_string("js_import"),
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE13,
ngx_js_import,
More information about the nginx-devel
mailing list