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,14 +264,14 @@ public static void generateGcPressure(double heapLoadFactor) {
243264 }
244265 }
245266
246- private static ReachabilityAnalyser <?> selectAnalyser () {
247- if ( OSUtils .isWindows ()) {
248- // On Windows there are problems with the Heap release, which prevents the headump file
249- // from being deleted.
250- return new GCAnalyser ();
251- } else {
252- return new HeapDumpAnalyser ();
253- }
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 ());
254275 }
255276
256277 private static String formatShortestGCRootPath (String message , Result result ) {
@@ -344,17 +365,6 @@ private Result() {
344365 this .heapDumpFile = null ;
345366 }
346367
347- Result (Reference <?> reference ) {
348- this .collected = false ;
349- this .reference = reference ;
350- this .gcRootKind = null ;
351- this .instanceId = -1 ;
352- this .shortestGCRootPath = null ;
353- this .gcRootThreadId = -1 ;
354- this .gcRootStackTrace = null ;
355- this .heapDumpFile = null ;
356- }
357-
358368 Result (Reference <?> reference , long instanceId , String gcRootKind , Iterable <? extends InstanceReference > shortestGCRootPath ,
359369 long gcRootThreadId , Iterable <? extends StackTraceElement > gcRootStackTrace , Path heapDumpFile ) {
360370 this .collected = false ;
@@ -674,60 +684,18 @@ private static HotSpotDiagnosticMXBean getHotSpotDiagnosticMBean() throws IOExce
674684 }
675685
676686 private static void delete (Path file ) throws IOException {
677- if (Files .isDirectory (file , LinkOption .NOFOLLOW_LINKS )) {
678- try (DirectoryStream <Path > content = Files .newDirectoryStream (file )) {
679- for (Path child : content ) {
680- delete (child );
681- }
682- }
683- }
684- Files .delete (file );
685- }
686- }
687-
688- private static final class GCAnalyser extends ReachabilityAnalyser <Void > {
689-
690- @ Override
691- Result analyse (Collection <? extends Reference <?>> references , boolean performAllocations , boolean collectGCRootPath ,
692- boolean preserveHeapDumpIfNonCollectable , Function <Void , Result > testCollected ) {
693- int blockSize = 100_000 ;
694- final List <byte []> blocks = new ArrayList <>();
695- Result result = null ;
696- for (int i = 0 ; i < 50 ; i ++) {
697- result = testCollected .apply (null );
698- if (result .isCollected ()) {
699- return result ;
700- }
701- try {
702- System .gc ();
703- } catch (OutOfMemoryError oom ) {
704- }
705- try {
706- System .runFinalization ();
707- } catch (OutOfMemoryError oom ) {
708- }
709- if (performAllocations ) {
710- try {
711- blocks .add (new byte [blockSize ]);
712- blockSize = (int ) (blockSize * 1.3 );
713- } catch (OutOfMemoryError oom ) {
714- blockSize >>>= 1 ;
715- }
716- }
717- if (i % 10 == 0 ) {
718- try {
719- Thread .sleep (500 );
720- } catch (InterruptedException ie ) {
721- 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+ }
722695 }
723696 }
697+ Files .delete (file );
724698 }
725- return result ;
726- }
727-
728- @ Override
729- Result isCollected (Reference <?> reference , Void context ) {
730- return reference .get () == null ? Result .COLLECTED : new Result (reference );
731699 }
732700 }
733701}
0 commit comments