]> git.kaiwu.me - njs.git/commitdiff
QuickJS: added memory limit check for reuse queue.
authorDmitry Volyntsev <xeioex@nginx.com>
Thu, 22 May 2025 00:10:15 +0000 (17:10 -0700)
committerDmitry Volyntsev <xeioexception@gmail.com>
Tue, 27 May 2025 22:20:36 +0000 (15:20 -0700)
nginx/ngx_http_js_module.c
nginx/ngx_js.c
nginx/ngx_js.h
nginx/ngx_stream_js_module.c

index 28798172ab43995c625ed28f0d635b43b8aa4a37..1e0a927f3dd534ed5f8a9ada255953ee60a7ad14 100644 (file)
@@ -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,
index e4bae32a393877414b9e81d2f39d8f42ed5154b7..515218b97416a1a7d1c4f0b444ec3699d65c061d 100644 (file)
@@ -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);
index 122881af5c1e3bb36930457878a5ce28ba39d34e..99330f8819fcc50be1029cf36d15da9e2e43284f 100644 (file)
@@ -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;                                           \
index fb58cdc63dc433c0f7691da0df36bbc862414eab..328ce5810686ebcdcf8a3851b0881a3995274de4 100644 (file)
@@ -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,