From b3aa0cfb93ffc2b6e4ada87ecba6f254e4711cf0 Mon Sep 17 00:00:00 2001 From: Vladislav Beskrovny Date: Tue, 18 Mar 2025 19:22:08 +0100 Subject: [PATCH] [platform] IJPL-181469 Run JBR `shrinkingGC()` when IDE becomes idle A `System.gc()` invocation can lead to the heap being shrunk based on the percentage of free memory. If the free memory percentage is higher than `-XX:MaxHeapFreeRatio` (70% by default), the heap is shrunk so that the percentage of free heap space is lower than `-XX:MaxHeapFreeRatio`. The recently introduced `shrinkingGC()` is mostly equivalent to `System.gc()` except it shrinks the heap respecting `-XX:JbrShrinkingGcMaxHeapFreeRatio` option instead of `-XX:MaxHeapFreeRatio`. With `-XX:JbrShrinkingGcMaxHeapFreeRatio=40` set, `shrinkingGC()` can shrink almost 2 times more than `System.gc()` GitOrigin-RevId: 5810093ee76baba2babb2a56f74bb02414c6d1c1 --- .../intellij/build/impl/VmOptionsGenerator.kt | 1 + .../src/com/intellij/ide/AppIdleMemoryCleaner.kt | 10 +++++++++- .../devkit-core/src/run/DevKitApplicationPatcher.kt | 3 +++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/platform/build-scripts/src/org/jetbrains/intellij/build/impl/VmOptionsGenerator.kt b/platform/build-scripts/src/org/jetbrains/intellij/build/impl/VmOptionsGenerator.kt index 1d65d44045a6..6e350e2ebcfa 100644 --- a/platform/build-scripts/src/org/jetbrains/intellij/build/impl/VmOptionsGenerator.kt +++ b/platform/build-scripts/src/org/jetbrains/intellij/build/impl/VmOptionsGenerator.kt @@ -14,6 +14,7 @@ object VmOptionsGenerator { @Suppress("SpellCheckingInspection") private val COMMON_VM_OPTIONS: List = listOf( + "-XX:JbrShrinkingGcMaxHeapFreeRatio=40", // IJPL-181469. Used in a couple with AppIdleMemoryCleaner.runGc() "-XX:ReservedCodeCacheSize=512m", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:-OmitStackTraceInFastThrow", diff --git a/platform/platform-impl/src/com/intellij/ide/AppIdleMemoryCleaner.kt b/platform/platform-impl/src/com/intellij/ide/AppIdleMemoryCleaner.kt index 6bd0898b7ad1..b6905c7053ac 100644 --- a/platform/platform-impl/src/com/intellij/ide/AppIdleMemoryCleaner.kt +++ b/platform/platform-impl/src/com/intellij/ide/AppIdleMemoryCleaner.kt @@ -28,6 +28,8 @@ import com.intellij.platform.ide.progress.updates import com.intellij.util.io.DirectByteBufferAllocator import com.intellij.util.io.StorageLockContext import com.intellij.util.io.storage.HeavyProcessLatch +import com.jetbrains.Extensions +import com.jetbrains.JBR import fleet.kernel.rete.asValuesFlow import fleet.kernel.rete.tokensFlow import fleet.kernel.tryWithEntities @@ -129,7 +131,13 @@ class AppIdleMemoryCleaner(private val cs: CoroutineScope) { private fun runGc() { // `System.gc()` makes the heap to shrink respecting `-XX:MaxHeapFreeRatio` VM option, so some memory is returned to OS. // At the same time, it leads to a long GC pause (hundreds of milliseconds). This should be OK since the IDE is idle. - System.gc() + val jbrSystemUtils = JBR.getSystemUtils(Extensions.SHRINKING_GC) + if (jbrSystemUtils != null) { + // Used in a couple with `-XX:JbrShrinkingGcMaxHeapFreeRatio` option + jbrSystemUtils.shrinkingGC() + } else { + System.gc() + } } } diff --git a/plugins/devkit/devkit-core/src/run/DevKitApplicationPatcher.kt b/plugins/devkit/devkit-core/src/run/DevKitApplicationPatcher.kt index 60126d601af8..70b84ba67662 100644 --- a/plugins/devkit/devkit-core/src/run/DevKitApplicationPatcher.kt +++ b/plugins/devkit/devkit-core/src/run/DevKitApplicationPatcher.kt @@ -97,6 +97,9 @@ private class DevKitApplicationPatcher : RunConfigurationExtension() { if (vmParametersAsList.none { it.startsWith("-Xmx") }) { vmParameters.add("-Xmx2g") } + if (vmParametersAsList.none { it.startsWith("-XX:JbrShrinkingGcMaxHeapFreeRatio=") }) { + vmParameters.add("-XX:JbrShrinkingGcMaxHeapFreeRatio=40") + } if (is17 && vmParametersAsList.none { it.startsWith("-XX:SoftRefLRUPolicyMSPerMB") }) { vmParameters.add("-XX:SoftRefLRUPolicyMSPerMB=50") }