Run a manual GC after clearing the in-memory graph from a `--keep_state_after_build` command.

Same purpose as unknown commit except for cases where the previous build kept state.

PiperOrigin-RevId: 550048302
Change-Id: I6bf3ef26edfcd9f63ff2f71790dd28f15de9d714
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
index 4cb7842..47b55e0 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SequencedSkyframeExecutor.java
@@ -55,6 +55,7 @@
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.packages.RuleClass;
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
+import com.google.devtools.build.lib.profiler.GoogleAutoProfilerUtils;
 import com.google.devtools.build.lib.profiler.Profiler;
 import com.google.devtools.build.lib.profiler.ProfilerTask;
 import com.google.devtools.build.lib.repository.ExternalPackageHelper;
@@ -123,6 +124,8 @@
   private boolean trackIncrementalState = true;
 
   private boolean evaluatorNeedsReset = false;
+  private boolean lastCommandKeptState = false;
+  private boolean needGcAfterResettingEvaluator = false;
 
   private final AtomicInteger outputDirtyFiles = new AtomicInteger();
   private final ArrayBlockingQueue<String> outputDirtyFilesExecPathSample =
@@ -258,6 +261,15 @@
       // or if the graph doesn't have edges, so that a fresh graph can be used.
       resetEvaluator();
       evaluatorNeedsReset = false;
+      if (needGcAfterResettingEvaluator) {
+        // Collect weakly reachable objects to avoid resurrection. See b/291641466.
+        try (var profiler =
+            GoogleAutoProfilerUtils.logged(
+                "manual GC to clean up from --keep_state_after_build command")) {
+          System.gc();
+        }
+        needGcAfterResettingEvaluator = false;
+      }
     }
     super.sync(
         eventHandler,
@@ -389,13 +401,17 @@
     }
 
     // Now check if it is necessary to wipe the previous state. We do this if either the previous
-    // or current incrementalStateRetentionStrategy requires the build to have been isolated.
+    // or current command requires the build to have been isolated.
     if (oldValueOfTrackIncrementalState != trackIncrementalState) {
       logger.atInfo().log("Set incremental state to %b", trackIncrementalState);
       evaluatorNeedsReset = true;
     } else if (!trackIncrementalState) {
       evaluatorNeedsReset = true;
     }
+    if (evaluatorNeedsReset && lastCommandKeptState) {
+      needGcAfterResettingEvaluator = true;
+    }
+    lastCommandKeptState = keepStateAfterBuild;
   }
 
   @Override