Hi Daniel,
Could you please sponsor the attached patch?
Webrev: http://cr.openjdk.java.net/~ykantser/8038822/webrev.01
The only change is that I have made BoundlessLoaderThread.pool final.
Mattias
----- Original Message -----
From: [email protected]
To: [email protected]
Cc: [email protected]
Sent: Thursday, April 3, 2014 4:41:46 PM GMT +01:00 Amsterdam / Berlin / Bern /
Rome / Stockholm / Vienna
Subject: Re: RFR 8038822: java/lang/management/MemoryMXBean/LowMemoryTest2.sh
still fails with OutOfMemoryError: Metaspace
Thanks for the feedback.
I first tried to call gc() unconditionally, but then the duration of the test
increased from 2 to 25 seconds. I was surprised it made such a difference.
I will make BoundlessLoaderThread.pool final.
Mattias
----- Original Message -----
From: [email protected]
To: [email protected], [email protected]
Sent: Thursday, April 3, 2014 4:03:45 PM GMT +01:00 Amsterdam / Berlin / Bern /
Rome / Stockholm / Vienna
Subject: Re: RFR 8038822: java/lang/management/MemoryMXBean/LowMemoryTest2.sh
still fails with OutOfMemoryError: Metaspace
Hi Mattias,
This looks good.
Maybe you could afford to call gc() unconditionally
instead of only when isAnyUsageAboveThreshold(pools) returns
true.
This may be taken into consideration if this test fails again ;-(
Small nit: BoundlessLoaderThread.pool could be declared final.
best regards,
-- daniel
On 4/3/14 1:58 PM, Mattias Tobiasson wrote:
> Hi,
> This test sometimes fails with OutOfMemory. It fails rarely, I have not been
> able to reproduce it.
>
> The test keeps loading new classes until
> MemoryMXBean.getUsageThresholdCount() > 0.
> UsageThresholdCount is only updated during a GC. My guess is that the test
> loads classes
> too fast so we run out of memory before the flag is set.
>
> This fix will force a GC when used memory is above the threshold.
> That should update the UsageThresholdCount immediately.
> I have also added more logging if the test fails again.
>
> changes:
> 1. Force a GC if memory usage is above threshold.
> 2. Split the big check pools loop into sub functions.
> 3. "pools" list only contains the relevant pools,
> instead of keeping all pools and filter them each loop.
>
> webrev: http://cr.openjdk.java.net/~ykantser/8038822/webrev.00
> bug: https://bugs.openjdk.java.net/browse/JDK-8038822
>
> Mattias
>
# HG changeset patch
# User mtobiass
# Date 1396609286 -7200
# Node ID d07974e1e7f60d7f8a15a5b61cfae2f57016fe85
# Parent 8ca451a7d41d8add5529cec32e17b85b585bb5f0
8038822: java/lang/management/MemoryMXBean/LowMemoryTest2.sh still fails with OutOfMemoryError: Metaspace
Summary: Force a GC when usage above threshold. Add more logging.
Reviewed-by: dfuchs
diff --git a/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java b/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java
--- a/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java
+++ b/test/java/lang/management/MemoryMXBean/LowMemoryTest2.java
@@ -64,6 +64,11 @@
// low memory notification
static class BoundlessLoaderThread extends ClassLoader implements Runnable {
+ private final List<MemoryPoolMXBean> pools;
+
+ public BoundlessLoaderThread(List<MemoryPoolMXBean> pools) {
+ this.pools = pools;
+ }
static int count = 100000;
@@ -139,26 +144,29 @@
* Then wait for the memory threshold notification to be received.
*/
public void run() {
- List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();
- boolean thresholdExceeded = false;
+ // Load classes until MemoryPoolMXBean.getUsageThresholdCount() > 0
+ boolean isThresholdCountSet = false;
+ try {
+ while (!isThresholdCountSet) {
+ // the classes are small so we load 10 at a time
+ for (int i=0; i<10; i++) {
+ loadNext();
+ }
- // Load classes until MemoryPoolMXBean.getUsageThresholdCount() > 0
- while (!thresholdExceeded) {
- // the classes are small so we load 10 at a time
- for (int i=0; i<10; i++) {
- loadNext();
+ if (isAnyUsageAboveThreshold(pools)) {
+ // UsageThresholdCount is only updated during GC.
+ // Force GC to update counters.
+ // If we don't force a GC we may get an
+ // OutOfMemoryException before the counters are updated.
+ System.out.println("Force GC");
+ System.gc();
+ }
+ isThresholdCountSet = isAnyThresholdCountSet(pools);
}
-
- // check if the threshold has been exceeded
- for (MemoryPoolMXBean p : pools) {
- if (p.getType() == MemoryType.NON_HEAP &&
- p.isUsageThresholdSupported() &&
- p.getUsageThresholdCount() > 0)
- {
- thresholdExceeded = true;
- break;
- }
- }
+ } catch (OutOfMemoryError e) {
+ e.printStackTrace();
+ MemoryUtil.printMemoryPools(pools);
+ throw e;
}
System.out.println("thresholdExceeded. Waiting for notification");
@@ -168,16 +176,39 @@
} catch (InterruptedException x) {}
}
}
+
+ private boolean isAnyUsageAboveThreshold(List<MemoryPoolMXBean> pools) {
+ for (MemoryPoolMXBean p : pools) {
+ if (p.isUsageThresholdExceeded()) {
+ System.out.println("isAnyUsageAboveThreshold is true for " + p.getName());
+ MemoryUtil.printMemoryPool(p);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isAnyThresholdCountSet(List<MemoryPoolMXBean> pools) {
+ for (MemoryPoolMXBean p : pools) {
+ if (p.getUsageThresholdCount() > 0) {
+ System.out.println("isAnyThresholdCountSet is true for " + p.getName());
+ MemoryUtil.printMemoryPool(p);
+ return true;
+ }
+ }
+ return false;
+ }
}
public static void main(String args[]) {
- List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();
+ // The pools list will only contain the pools that we are interested in.
+ List<MemoryPoolMXBean> pools = new ArrayList<MemoryPoolMXBean>();
// Set threshold of 80% of all NON_HEAP memory pools
// In the Hotspot implementation this means we should get a notification
// if the CodeCache or metaspace fills up.
- for (MemoryPoolMXBean p : pools) {
+ for (MemoryPoolMXBean p : ManagementFactory.getMemoryPoolMXBeans()) {
if (p.getType() == MemoryType.NON_HEAP && p.isUsageThresholdSupported()) {
// set threshold
@@ -190,6 +221,7 @@
long threshold = (max * 80) / 100;
p.setUsageThreshold(threshold);
+ pools.add(p);
System.out.println("Selected memory pool for low memory " +
"detection.");
@@ -209,7 +241,7 @@
// Start the thread loading classes
- Thread thr = new Thread(new BoundlessLoaderThread());
+ Thread thr = new Thread(new BoundlessLoaderThread(pools));
thr.start();
// Wait for the thread to terminate
diff --git a/test/java/lang/management/MemoryMXBean/MemoryUtil.java b/test/java/lang/management/MemoryMXBean/MemoryUtil.java
--- a/test/java/lang/management/MemoryMXBean/MemoryUtil.java
+++ b/test/java/lang/management/MemoryMXBean/MemoryUtil.java
@@ -54,6 +54,8 @@
pool.getUsage());
System.out.println(INDENT + "Threshold: " +
(pool.isUsageThresholdSupported() ? pool.getUsageThreshold() : -1));
+ System.out.println(INDENT + "ThresholdCount: " +
+ (pool.isUsageThresholdSupported() ? pool.getUsageThresholdCount() : -1));
System.out.print(INDENT + "Manager = [");
String[] mgrs = pool.getMemoryManagerNames();
for (int i = 0; i < mgrs.length; i++) {