oracle/graal · error · GraalError

too many counters, reduce number of counters or increase -XX

Error message

too many counters, reduce number of counters or increase -XX:JVMCICounterSize=... (current value: %s)

What it means

GraalError thrown by BenchmarkCounters when a newly allocated counter's index exceeds the native counter array size given by -XX:JVMCICounterSize. The HotSpot side pre-allocates a fixed-size array shared by all benchmark counters; the Java side checks each new (name, group) pair fits. Too many distinct counter names exhaust the array.

Source

Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/debug/BenchmarkCounters.java:181

    private static Counter getCounter(String name, String group, GraalHotSpotVMConfig config) throws GraalError {
        if (!enabled) {
            throw new GraalError("cannot access count index when counters are not enabled: " + group + ", " + name);
        }
        String nameGroup = name + "#" + group;
        Counter counter = counterMap.get(nameGroup);
        if (counter == null) {
            synchronized (BenchmarkCounters.class) {
                counter = counterMap.get(nameGroup);
                if (counter == null) {
                    counter = new Counter(counterMap.size(), group, new AtomicLong());
                    counterMap.put(nameGroup, counter);
                }
            }
        }
        assert counter.group.equals(group) : "mismatching groups: " + counter.group + " vs. " + group;
        int countersSize = config.jvmciCountersSize;
        if (counter.index >= countersSize) {
            throw new GraalError("too many counters, reduce number of counters or increase -XX:JVMCICounterSize=... (current value: " + countersSize + ")");
        }
        return counter;
    }

    private static synchronized void dump(OptionValues options, PrintStream out, double seconds, long[] counters, int maxRows) {
        if (!counterMap.isEmpty()) {
            try (Dumper dumper = Dumper.getDumper(options, out, counterMap.size(), seconds, maxRows)) {
                TreeSet<String> set = new TreeSet<>();
                counterMap.forEach((nameGroup, counter) -> set.add(counter.group));
                for (String group : set) {
                    if (group != null) {
                        if (Options.BenchmarkCountersDumpStatic.getValue(options)) {
                            dumper.dumpCounters(true, group, collectStaticCounters(), counterMap.entrySet(), options);
                        }
                        if (Options.BenchmarkCountersDumpDynamic.getValue(options)) {
                            dumper.dumpCounters(false, group, collectDynamicCounters(counters), counterMap.entrySet(), options);
                        }
                    }

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Increase the native array: add -XX:JVMCICounterSize=<larger> (e.g. 65536) to the command line.
  2. Reduce counter churn by disabling counter types you do not need (-Dgraal.BenchmarkCounters=false, generic dynamic counters off).
  3. Scope the run to fewer methods/benchmarks so fewer unique counters are allocated.

Example fix

# before
-XX:+UseJVMCICompiler -Dgraal.GenericDynamicCounters=true
# GraalError: too many counters

# after
-XX:+UseJVMCICompiler -Dgraal.GenericDynamicCounters=true -XX:JVMCICounterSize=65536
Defensive patterns

Strategy: validation

Validate before calling

# Pre-flight: scale JVMCICounterSize to expected counter count before launching
if [ -n "$GRAAL_COUNTERS_ENABLED" ]; then
  export JAVA_OPTS="$JAVA_OPTS -XX:JVMCICounterSize=${JVMCI_COUNTER_SIZE:-65536}"
fi

Try / catch

try {
    // workload with benchmark counters enabled
} catch (com.oracle.graal.compiler.GraalError e) { // jdk.graal.compiler.core.common.GraalError
    if (e.getMessage().contains("JVMCICounterSize")) {
        // relaunch with a larger -XX:JVMCICounterSize
    }
    throw e;
}

Prevention

When it happens

Trigger: Enabling -Dgraal.GenericDynamicCounters / -Dgraal.BenchmarkCounters and compiling enough distinct methods/nodes that the number of unique counters exceeds the default JVMCICounterSize array bound; counters are created lazily per name-group, so long runs or wide benchmarks cross the limit.

Common situations: Running large benchmark suites or full applications with benchmark counters enabled; lowering JVMCICounterSize for memory reasons and then hitting more counters than slots.

Related errors


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/ea762a7684632383. Report an issue: GitHub.