Add a option to disable idle gc.
If a Bazel server is idle for 10 seconds, it unconditionally triggers a full-scale Java GC via System.gc(). This behavior doesn't have clear benefits and causes Bazel to steal resources from whatever the user does after invoking Bazel. This CL adds a startup option, --idle_server_tasks, to toggle the idle GC behavior.
Also, add some logging for when idle GC is enabled, so it's easier to evaluate its effects. Example of logging:
```
180718 17:43:04.609:I 247 [com.google.devtools.build.lib.server.IdleServerTasks.lambda$idle$0] [Idle GC] used: 157MB -> 15MB, committed: 421MB -> 422MB
```
Fixes https://github.com/bazelbuild/bazel/issues/5589.
Closes #5628.
PiperOrigin-RevId: 207869996
diff --git a/src/main/java/com/google/devtools/build/lib/server/IdleServerTasks.java b/src/main/java/com/google/devtools/build/lib/server/IdleServerTasks.java
index 01e596a..d8cb41a 100644
--- a/src/main/java/com/google/devtools/build/lib/server/IdleServerTasks.java
+++ b/src/main/java/com/google/devtools/build/lib/server/IdleServerTasks.java
@@ -16,6 +16,10 @@
import com.google.common.base.Preconditions;
import com.google.devtools.build.lib.profiler.AutoProfiler;
+import com.google.devtools.build.lib.util.StringUtilities;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryUsage;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@@ -29,9 +33,7 @@
private final ScheduledThreadPoolExecutor executor;
private static final Logger logger = Logger.getLogger(IdleServerTasks.class.getName());
- /**
- * Must be called from the main thread.
- */
+ /** Must be called from the main thread. */
public IdleServerTasks() {
this.executor = new ScheduledThreadPoolExecutor(1);
}
@@ -43,14 +45,23 @@
public void idle() {
Preconditions.checkState(!executor.isShutdown());
- // Do a GC cycle while the server is idle.
@SuppressWarnings("unused")
Future<?> possiblyIgnoredError =
executor.schedule(
() -> {
+ MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
+ MemoryUsage before = memBean.getHeapMemoryUsage();
try (AutoProfiler p = AutoProfiler.logged("Idle GC", logger)) {
System.gc();
}
+ MemoryUsage after = memBean.getHeapMemoryUsage();
+ logger.info(
+ String.format(
+ "[Idle GC] used: %s -> %s, committed: %s -> %s",
+ StringUtilities.prettyPrintBytes(before.getUsed()),
+ StringUtilities.prettyPrintBytes(after.getUsed()),
+ StringUtilities.prettyPrintBytes(before.getCommitted()),
+ StringUtilities.prettyPrintBytes(after.getCommitted())));
},
10,
TimeUnit.SECONDS);