8240679: ZGC GarbageCollectorMXBean reports inaccurate post GC heap size for ZHeap pool

Reviewed-by: eosterlund
This commit is contained in:
Per Lidén 2020-04-30 10:59:23 +02:00
parent 05b3bc57ac
commit 68e53065e0
8 changed files with 363 additions and 113 deletions

@ -164,7 +164,7 @@ public:
virtual bool do_operation() {
ZStatTimer timer(ZPhasePauseMarkStart);
ZServiceabilityMarkStartTracer tracer;
ZServiceabilityPauseTracer tracer;
// Set up soft reference policy
const bool clear = should_clear_soft_references();
@ -189,7 +189,7 @@ public:
virtual bool do_operation() {
ZStatTimer timer(ZPhasePauseMarkEnd);
ZServiceabilityMarkEndTracer tracer;
ZServiceabilityPauseTracer tracer;
return ZHeap::heap()->mark_end();
}
};
@ -206,7 +206,7 @@ public:
virtual bool do_operation() {
ZStatTimer timer(ZPhasePauseRelocateStart);
ZServiceabilityRelocateStartTracer tracer;
ZServiceabilityPauseTracer tracer;
ZHeap::heap()->relocate_start();
return true;
}
@ -354,17 +354,19 @@ void ZDriver::check_out_of_memory() {
class ZDriverGCScope : public StackObj {
private:
GCIdMark _gc_id;
GCCause::Cause _gc_cause;
GCCauseSetter _gc_cause_setter;
ZStatTimer _timer;
GCIdMark _gc_id;
GCCause::Cause _gc_cause;
GCCauseSetter _gc_cause_setter;
ZStatTimer _timer;
ZServiceabilityCycleTracer _tracer;
public:
ZDriverGCScope(GCCause::Cause cause) :
_gc_id(),
_gc_cause(cause),
_gc_cause_setter(ZCollectedHeap::heap(), cause),
_timer(ZPhaseCycle) {
_timer(ZPhaseCycle),
_tracer() {
// Update statistics
ZStatCycle::at_start();
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -138,25 +138,23 @@ ZServiceabilityCounters* ZServiceability::counters() {
return _counters;
}
ZServiceabilityMemoryUsageTracker::~ZServiceabilityMemoryUsageTracker() {
ZServiceabilityCycleTracer::ZServiceabilityCycleTracer() :
_memory_manager_stats(ZHeap::heap()->serviceability_memory_manager(),
ZCollectedHeap::heap()->gc_cause(),
true /* allMemoryPoolsAffected */,
true /* recordGCBeginTime */,
true /* recordPreGCUsage */,
true /* recordPeakUsage */,
true /* recordPostGCUsage */,
true /* recordAccumulatedGCTime */,
true /* recordGCEndTime */,
true /* countCollection */) {}
ZServiceabilityPauseTracer::ZServiceabilityPauseTracer() :
_svc_gc_marker(SvcGCMarker::CONCURRENT),
_counters_stats(ZHeap::heap()->serviceability_counters()->collector_counters()) {}
ZServiceabilityPauseTracer::~ZServiceabilityPauseTracer() {
ZHeap::heap()->serviceability_counters()->update_sizes();
MemoryService::track_memory_usage();
}
ZServiceabilityManagerStatsTracer::ZServiceabilityManagerStatsTracer(bool is_gc_begin, bool is_gc_end) :
_stats(ZHeap::heap()->serviceability_memory_manager(),
ZCollectedHeap::heap()->gc_cause() /* cause */,
true /* allMemoryPoolsAffected */,
is_gc_begin /* recordGCBeginTime */,
is_gc_begin /* recordPreGCUsage */,
true /* recordPeakUsage */,
is_gc_end /* recordPostGCusage */,
true /* recordAccumulatedGCTime */,
is_gc_end /* recordGCEndTime */,
is_gc_end /* countCollection */) {}
ZServiceabilityCountersTracer::ZServiceabilityCountersTracer() :
_stats(ZHeap::heap()->serviceability_counters()->collector_counters()) {}
ZServiceabilityCountersTracer::~ZServiceabilityCountersTracer() {
ZHeap::heap()->serviceability_counters()->update_sizes();
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -64,46 +64,22 @@ public:
ZServiceabilityCounters* counters();
};
class ZServiceabilityMemoryUsageTracker {
public:
~ZServiceabilityMemoryUsageTracker();
};
class ZServiceabilityManagerStatsTracer {
class ZServiceabilityCycleTracer : public StackObj {
private:
TraceMemoryManagerStats _stats;
TraceMemoryManagerStats _memory_manager_stats;
public:
ZServiceabilityManagerStatsTracer(bool is_gc_begin, bool is_gc_end);
ZServiceabilityCycleTracer();
};
class ZServiceabilityCountersTracer {
class ZServiceabilityPauseTracer : public StackObj {
private:
TraceCollectorStats _stats;
SvcGCMarker _svc_gc_marker;
TraceCollectorStats _counters_stats;
public:
ZServiceabilityCountersTracer();
~ZServiceabilityCountersTracer();
ZServiceabilityPauseTracer();
~ZServiceabilityPauseTracer();
};
template <bool IsGCStart, bool IsGCEnd>
class ZServiceabilityTracer : public StackObj {
private:
SvcGCMarker _svc_gc_marker;
ZServiceabilityMemoryUsageTracker _memory_usage_tracker;
ZServiceabilityManagerStatsTracer _manager_stats_tracer;
ZServiceabilityCountersTracer _counters_tracer;
public:
ZServiceabilityTracer() :
_svc_gc_marker(SvcGCMarker::CONCURRENT),
_memory_usage_tracker(),
_manager_stats_tracer(IsGCStart, IsGCEnd),
_counters_tracer() {}
};
typedef ZServiceabilityTracer<true, false> ZServiceabilityMarkStartTracer;
typedef ZServiceabilityTracer<false, false> ZServiceabilityMarkEndTracer;
typedef ZServiceabilityTracer<false, true> ZServiceabilityRelocateStartTracer;
#endif // SHARE_GC_Z_ZSERVICEABILITY_HPP

@ -0,0 +1,171 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test TestGarbageCollectorMXBean
* @requires vm.gc.Z & !vm.graal.enabled
* @summary Test ZGC garbage collector MXBean
* @modules java.management
* @run main/othervm -XX:+UseZGC -Xms256M -Xmx512M -Xlog:gc TestGarbageCollectorMXBean 256 512
* @run main/othervm -XX:+UseZGC -Xms512M -Xmx512M -Xlog:gc TestGarbageCollectorMXBean 512 512
*/
import java.lang.management.ManagementFactory;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import javax.management.Notification;
import javax.management.NotificationBroadcaster;
import javax.management.NotificationListener;
import javax.management.openmbean.CompositeData;
import com.sun.management.GarbageCollectionNotificationInfo;
public class TestGarbageCollectorMXBean {
public static void main(String[] args) throws Exception {
final long M = 1024 * 1024;
final long initialCapacity = Long.parseLong(args[0]) * M;
final long maxCapacity = Long.parseLong(args[1]) * M;
final AtomicInteger cycles = new AtomicInteger();
final AtomicInteger errors = new AtomicInteger();
final NotificationListener listener = (Notification notification, Object ignored) -> {
final var type = notification.getType();
if (!type.equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) {
// Ignore
return;
}
final var data = (CompositeData)notification.getUserData();
final var info = GarbageCollectionNotificationInfo.from(data);
final var name = info.getGcName();
final var id = info.getGcInfo().getId();
final var action = info.getGcAction();
final var cause = info.getGcCause();
final var startTime = info.getGcInfo().getStartTime();
final var endTime = info.getGcInfo().getEndTime();
final var duration = info.getGcInfo().getDuration();
final var memoryUsageBeforeGC = info.getGcInfo().getMemoryUsageBeforeGc().get("ZHeap");
final var memoryUsageAfterGC = info.getGcInfo().getMemoryUsageAfterGc().get("ZHeap");
System.out.println(name + " (" + type + ")");
System.out.println(" Id: " + id);
System.out.println(" Action: " + action);
System.out.println(" Cause: " + cause);
System.out.println(" StartTime: " + startTime);
System.out.println(" EndTime: " + endTime);
System.out.println(" Duration: " + duration);
System.out.println(" MemoryUsageBeforeGC: " + memoryUsageBeforeGC);
System.out.println(" MemoryUsageAfterGC: " + memoryUsageAfterGC);
System.out.println();
if (name.equals("ZGC")) {
cycles.incrementAndGet();
} else {
System.out.println("ERROR: Name");
errors.incrementAndGet();
}
if (!action.equals("end of major GC")) {
System.out.println("ERROR: Action");
errors.incrementAndGet();
}
if (memoryUsageBeforeGC.getInit() != initialCapacity) {
System.out.println("ERROR: MemoryUsageBeforeGC.init");
errors.incrementAndGet();
}
if (memoryUsageBeforeGC.getUsed() > initialCapacity) {
System.out.println("ERROR: MemoryUsageBeforeGC.used");
errors.incrementAndGet();
}
if (memoryUsageBeforeGC.getCommitted() != initialCapacity) {
System.out.println("ERROR: MemoryUsageBeforeGC.committed");
errors.incrementAndGet();
}
if (memoryUsageBeforeGC.getMax() != maxCapacity) {
System.out.println("ERROR: MemoryUsageBeforeGC.max");
errors.incrementAndGet();
}
if (!cause.equals("System.gc()")) {
System.out.println("ERROR: Cause");
errors.incrementAndGet();
}
if (startTime > endTime) {
System.out.println("ERROR: StartTime");
errors.incrementAndGet();
}
if (endTime - startTime != duration) {
System.out.println("ERROR: Duration");
errors.incrementAndGet();
}
};
// Collect garbage created at startup
System.gc();
// Register GC event listener
for (final var collector : ManagementFactory.getGarbageCollectorMXBeans()) {
final NotificationBroadcaster broadcaster = (NotificationBroadcaster)collector;
broadcaster.addNotificationListener(listener, null, null);
}
final int minCycles = 5;
// Run GCs
for (int i = 0; i < minCycles; i++) {
System.gc();
}
// Wait at most 60 seconds
for (int i = 0; i < 60; i++) {
Thread.sleep(1000);
if (cycles.get() >= minCycles) {
// All events received
break;
}
}
final int actualCycles = cycles.get();
final int actualErrors = errors.get();
System.out.println(" minCycles: " + minCycles);
System.out.println("actualCycles: " + actualCycles);
System.out.println("actualErrors: " + actualErrors);
// Verify number of cycle events
if (cycles.get() < minCycles) {
throw new Exception("Unexpected cycles");
}
// Verify number of errors
if (actualErrors != 0) {
throw new Exception("Unexpected errors");
}
}
}

@ -0,0 +1,63 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test TestMemoryMXBean
* @requires vm.gc.Z & !vm.graal.enabled
* @summary Test ZGC heap memory MXBean
* @modules java.management
* @run main/othervm -XX:+UseZGC -Xms128M -Xmx256M -Xlog:gc* TestMemoryMXBean 128 256
* @run main/othervm -XX:+UseZGC -Xms256M -Xmx256M -Xlog:gc* TestMemoryMXBean 256 256
*/
import java.lang.management.ManagementFactory;
public class TestMemoryMXBean {
public static void main(String[] args) throws Exception {
final long M = 1024 * 1024;
final long expectedInitialCapacity = Long.parseLong(args[0]) * M;
final long expectedMaxCapacity = Long.parseLong(args[1]) * M;
final var memoryUsage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
final long initialCapacity = memoryUsage.getInit();
final long capacity = memoryUsage.getCommitted();
final long maxCapacity = memoryUsage.getMax();
System.out.println("expectedInitialCapacity: " + expectedInitialCapacity);
System.out.println(" expectedMaxCapacity: " + expectedMaxCapacity);
System.out.println(" initialCapacity: " + initialCapacity);
System.out.println(" capacity: " + capacity);
System.out.println(" maxCapacity: " + maxCapacity);
if (initialCapacity != expectedInitialCapacity) {
throw new Exception("Unexpected initial capacity");
}
if (maxCapacity != expectedMaxCapacity) {
throw new Exception("Unexpected max capacity");
}
if (capacity < initialCapacity || capacity > maxCapacity) {
throw new Exception("Unexpected capacity");
}
}
}

@ -0,0 +1,78 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test TestMemoryManagerMXBean
* @requires vm.gc.Z & !vm.graal.enabled
* @summary Test ZGC memory manager MXBean
* @modules java.management
* @run main/othervm -XX:+UseZGC -Xmx128M TestMemoryManagerMXBean
*/
import java.lang.management.ManagementFactory;
public class TestMemoryManagerMXBean {
private static void checkName(String name) throws Exception {
if (name == null || name.length() == 0) {
throw new Exception("Invalid name");
}
}
public static void main(String[] args) throws Exception {
int zgcMemoryManagers = 0;
int zgcMemoryPools = 0;
for (final var memoryManager : ManagementFactory.getMemoryManagerMXBeans()) {
final var memoryManagerName = memoryManager.getName();
checkName(memoryManagerName);
System.out.println("MemoryManager: " + memoryManagerName);
if (memoryManagerName.equals("ZGC")) {
zgcMemoryManagers++;
}
for (final var memoryPoolName : memoryManager.getMemoryPoolNames()) {
checkName(memoryPoolName);
System.out.println(" MemoryPool: " + memoryPoolName);
if (memoryPoolName.equals("ZHeap")) {
zgcMemoryPools++;
}
}
if (zgcMemoryManagers != zgcMemoryPools) {
throw new Exception("MemoryManagers/MemoryPools mismatch");
}
}
if (zgcMemoryManagers != 1) {
throw new Exception("All MemoryManagers not found");
}
if (zgcMemoryPools != 1) {
throw new Exception("All MemoryPools not found");
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -33,6 +33,18 @@
* @run main MemoryTest 2 3
*/
/*
* @test
* @bug 4530538
* @summary Basic unit test of MemoryMXBean.getMemoryPools() and
* MemoryMXBean.getMemoryManager().
* @requires vm.gc == "Z"
* @author Mandy Chung
*
* @modules jdk.management
* @run main MemoryTest 1 1
*/
/*
* NOTE: This expected result is hardcoded in this test and this test
* will be affected if the heap memory layout is changed in

@ -1,50 +0,0 @@
#
# Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
#
# @test
# @requires vm.gc.Z
# @run compile MemoryTest.java
# @run shell MemoryTestZGC.sh
#
#Set appropriate jdk
if [ ! -z "${TESTJAVA}" ] ; then
jdk="$TESTJAVA"
else
echo "--Error: TESTJAVA must be defined as the pathname of a jdk to test."
exit 1
fi
runOne()
{
echo "runOne $@"
$TESTJAVA/bin/java ${TESTVMOPTS} -classpath $TESTCLASSES $@ || exit 2
}
# Test MemoryTest with ZGC. ZGC is a single generation GC, which means
# it has one memory manager and one memory pool.
runOne -XX:+UseZGC MemoryTest 1 1
exit 0