4343import java .io .BufferedInputStream ;
4444import java .io .BufferedOutputStream ;
4545import java .io .IOException ;
46+ import java .io .PrintStream ;
4647import java .lang .management .ManagementFactory ;
4748import java .lang .ref .Reference ;
4849import java .lang .ref .WeakReference ;
@@ -97,7 +98,7 @@ public final class GCUtils {
9798 */
9899 private static final String SAVE_HEAP_DUMP_TO = System .getProperty (GCUtils .class .getSimpleName () + ".saveHeapDumpTo" );
99100
100- private static final ReachabilityAnalyser <?> analyser = selectAnalyser ();
101+ private static final ReachabilityAnalyser <?> analyser = new HeapDumpAnalyser ();
101102
102103 private GCUtils () {
103104 throw new IllegalStateException ("No instance allowed." );
@@ -115,6 +116,10 @@ private GCUtils() {
115116 * @param objectFactory producer of collectible object per an iteration
116117 */
117118 public static void assertObjectsCollectible (Function <Integer , Object > objectFactory ) {
119+ if (!isSupported ()) {
120+ emitHeapDumpNotSupportedWarning ("assertObjectsCollectible" );
121+ return ;
122+ }
118123 List <Reference <Object >> collectibleObjects = new ArrayList <>();
119124 for (int i = 0 ; i < GC_TEST_ITERATIONS ; i ++) {
120125 collectibleObjects .add (new WeakReference <>(objectFactory .apply (i )));
@@ -138,6 +143,10 @@ public static void assertObjectsCollectible(Function<Integer, Object> objectFact
138143 * @see #assertGc(Collection)
139144 */
140145 public static void assertGc (String message , Reference <?> ref ) {
146+ if (!isSupported ()) {
147+ emitHeapDumpNotSupportedWarning ("assertGc" );
148+ return ;
149+ }
141150 Result result = analyser .allCollected (Collections .singleton (ref ), true , true , PRESERVE_HEAP_DUMP_ON_FAILURE );
142151 if (!result .isCollected ()) {
143152 Assert .fail (formatShortestGCRootPath (message , result ));
@@ -154,6 +163,10 @@ public static void assertGc(String message, Reference<?> ref) {
154163 * @param refs references their referents are to be released
155164 */
156165 public static void assertGc (String message , Collection <? extends Reference <?>> refs ) {
166+ if (!isSupported ()) {
167+ emitHeapDumpNotSupportedWarning ("assertGc" );
168+ return ;
169+ }
157170 Result result = analyser .allCollected (refs , true , true , PRESERVE_HEAP_DUMP_ON_FAILURE );
158171 if (!result .isCollected ()) {
159172 Assert .fail (formatShortestGCRootPath (message , result ));
@@ -170,6 +183,10 @@ public static void assertGc(String message, Collection<? extends Reference<?>> r
170183 * {@link AssertionError} thrown when the referent is not freed by the GC
171184 */
172185 public static void assertGc (Collection <? extends Pair <String , Reference <?>>> refsWithMessages ) {
186+ if (!isSupported ()) {
187+ emitHeapDumpNotSupportedWarning ("assertGc" );
188+ return ;
189+ }
173190 Map <Reference <?>, String > refsMap = new IdentityHashMap <>();
174191 for (Pair <String , Reference <?>> pair : refsWithMessages ) {
175192 refsMap .putIfAbsent (pair .getRight (), pair .getLeft ());
@@ -188,6 +205,10 @@ public static void assertGc(Collection<? extends Pair<String, Reference<?>>> ref
188205 * @param ref the reference
189206 */
190207 public static void assertNotGc (final String message , final Reference <?> ref ) {
208+ if (!isSupported ()) {
209+ emitHeapDumpNotSupportedWarning ("assertNotGc" );
210+ return ;
211+ }
191212 if (analyser .allCollected (Collections .singleton (ref ), false , false , false ).isCollected ()) {
192213 Assert .fail (message );
193214 }
@@ -243,15 +264,14 @@ public static void generateGcPressure(double heapLoadFactor) {
243264 }
244265 }
245266
246- private static ReachabilityAnalyser <?> selectAnalyser () {
247- if (ImageInfo .inImageCode () || OSUtils .isWindows ()) {
248- // In the native-image, the heap dump to slow to be used.
249- // On Windows there are problems with the Heap release, which prevents the headump file
250- // from being deleted.
251- return new GCAnalyser ();
252- } else {
253- return new HeapDumpAnalyser ();
254- }
267+ public static boolean isSupported () {
268+ return !ImageInfo .inImageRuntimeCode () || !OSUtils .isWindows ();
269+ }
270+
271+ private static void emitHeapDumpNotSupportedWarning (String method ) {
272+ PrintStream err = System .err ;
273+ err .printf ("[GCUtils] Ignoring GCUtils.%s: heap dump not supported in native-image on %s.%n" ,
274+ method , OSUtils .getCurrent ());
255275 }
256276
257277 private static String formatShortestGCRootPath (String message , Result result ) {
@@ -345,17 +365,6 @@ private Result() {
345365 this .heapDumpFile = null ;
346366 }
347367
348- Result (Reference <?> reference ) {
349- this .collected = false ;
350- this .reference = reference ;
351- this .gcRootKind = null ;
352- this .instanceId = -1 ;
353- this .shortestGCRootPath = null ;
354- this .gcRootThreadId = -1 ;
355- this .gcRootStackTrace = null ;
356- this .heapDumpFile = null ;
357- }
358-
359368 Result (Reference <?> reference , long instanceId , String gcRootKind , Iterable <? extends InstanceReference > shortestGCRootPath ,
360369 long gcRootThreadId , Iterable <? extends StackTraceElement > gcRootStackTrace , Path heapDumpFile ) {
361370 this .collected = false ;
@@ -675,60 +684,18 @@ private static HotSpotDiagnosticMXBean getHotSpotDiagnosticMBean() throws IOExce
675684 }
676685
677686 private static void delete (Path file ) throws IOException {
678- if (Files .isDirectory (file , LinkOption .NOFOLLOW_LINKS )) {
679- try (DirectoryStream <Path > content = Files .newDirectoryStream (file )) {
680- for (Path child : content ) {
681- delete (child );
682- }
683- }
684- }
685- Files .delete (file );
686- }
687- }
688-
689- private static final class GCAnalyser extends ReachabilityAnalyser <Void > {
690-
691- @ Override
692- Result analyse (Collection <? extends Reference <?>> references , boolean performAllocations , boolean collectGCRootPath ,
693- boolean preserveHeapDumpIfNonCollectable , Function <Void , Result > testCollected ) {
694- int blockSize = 100_000 ;
695- final List <byte []> blocks = new ArrayList <>();
696- Result result = null ;
697- for (int i = 0 ; i < 50 ; i ++) {
698- result = testCollected .apply (null );
699- if (result .isCollected ()) {
700- return result ;
701- }
702- try {
703- System .gc ();
704- } catch (OutOfMemoryError oom ) {
705- }
706- try {
707- System .runFinalization ();
708- } catch (OutOfMemoryError oom ) {
709- }
710- if (performAllocations ) {
711- try {
712- blocks .add (new byte [blockSize ]);
713- blockSize = (int ) (blockSize * 1.3 );
714- } catch (OutOfMemoryError oom ) {
715- blockSize >>>= 1 ;
716- }
717- }
718- if (i % 10 == 0 ) {
719- try {
720- Thread .sleep (500 );
721- } catch (InterruptedException ie ) {
722- break ;
687+ // On Windows there are problems with the Heap release, which prevents the headump file
688+ // from being deleted.
689+ if (OSUtils .getCurrent () != OSUtils .OS .Windows ) {
690+ if (Files .isDirectory (file , LinkOption .NOFOLLOW_LINKS )) {
691+ try (DirectoryStream <Path > content = Files .newDirectoryStream (file )) {
692+ for (Path child : content ) {
693+ delete (child );
694+ }
723695 }
724696 }
697+ Files .delete (file );
725698 }
726- return result ;
727- }
728-
729- @ Override
730- Result isCollected (Reference <?> reference , Void context ) {
731- return reference .get () == null ? Result .COLLECTED : new Result (reference );
732699 }
733700 }
734701}
0 commit comments