diff --git a/core/src/main/java/lucee/runtime/CFMLFactoryImpl.java b/core/src/main/java/lucee/runtime/CFMLFactoryImpl.java index 42bf5d47b2..d16100f03b 100644 --- a/core/src/main/java/lucee/runtime/CFMLFactoryImpl.java +++ b/core/src/main/java/lucee/runtime/CFMLFactoryImpl.java @@ -28,6 +28,7 @@ import java.util.NoSuchElementException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.atomic.AtomicInteger; import jakarta.servlet.Servlet; import jakarta.servlet.ServletConfig; @@ -88,10 +89,12 @@ public final class CFMLFactoryImpl extends CFMLFactory { private static final long MAX_AGE = 5 * 60000; // 5 minutes private static final int MAX_SIZE = 10000; + private static final int MAX_POOLED_PCS = Caster.toIntValue( SystemUtil.getSystemPropOrEnvVar( "lucee.pagecontext.pool.maxsize", null ), 100 ); private static final String LOG_TYPE_NAME = "factory"; private static JspEngineInfo info = new JspEngineInfoImpl("1.0"); private ConfigWebPro config; ConcurrentLinkedDeque pcs = new ConcurrentLinkedDeque(); + private final AtomicInteger pcsSize = new AtomicInteger(0); private final Map runningPcs = new ConcurrentHashMap(); private final Map runningChildPcs = new ConcurrentHashMap(); @@ -141,8 +144,9 @@ private static int getSystemPropOrEnvVarAsInt(String name) { */ @Override public void resetPageContext() { - LogUtil.log(config, Log.LEVEL_INFO, CFMLFactoryImpl.class.getName(), "Reset " + pcs.size() + " Unused PageContexts"); + LogUtil.log(config, Log.LEVEL_INFO, CFMLFactoryImpl.class.getName(), "Reset " + pcsSize.get() + " Unused PageContexts"); pcs.clear(); + pcsSize.set(0); Iterator it = runningPcs.values().iterator(); while (it.hasNext()) { it.next().reset(); @@ -229,6 +233,7 @@ public PageContextImpl getPageContextImpl(HttpServlet servlet, HttpServletReques else { try { pc = pcs.pop(); + pcsSize.decrementAndGet(); } catch (NoSuchElementException nsee) { pc = null; @@ -302,8 +307,10 @@ public void releaseLuceePageContext(PageContext pc, boolean unregisterFromThread ((PageContextImpl) parent).removeChildPageContext(pc); } } - if (pcs.size() < 100 && ((PageContextImpl) pc).getTimeoutStackTrace() == null && reuse)// not more than 100 PCs + if (pcsSize.get() < MAX_POOLED_PCS && ((PageContextImpl) pc).getTimeoutStackTrace() == null && reuse) {// not more than 100 PCs pcs.push((PageContextImpl) pc); + pcsSize.incrementAndGet(); + } if (runningPcs.size() > MAX_SIZE) clean(runningPcs); if (runningChildPcs.size() > MAX_SIZE) clean(runningChildPcs); diff --git a/core/src/main/java/resource/setting/sysprop-envvar.json b/core/src/main/java/resource/setting/sysprop-envvar.json index 948734a4af..1dccbd3031 100644 --- a/core/src/main/java/resource/setting/sysprop-envvar.json +++ b/core/src/main/java/resource/setting/sysprop-envvar.json @@ -594,6 +594,15 @@ "type": "string", "default": "https://oss.sonatype.org/content/repositories/snapshots/" }, + { + "sysprop": "lucee.pageContext.pool.maxsize", + "envvar": "LUCEE_PAGECONTEXT_POOL_MAXSIZE", + "desc": "Maximum number of PageContext instances to pool for reuse. Pooling reduces object allocation overhead. Higher values use more memory but improve performance under high concurrency", + "category": "performance", + "type": "numeric", + "introduced": "7.1.0.8", + "default": 100 + }, { "sysprop": "lucee.pagePool.maxSize", "envvar": "LUCEE_PAGEPOOL_MAXSIZE",