Skip to content

[GR-38413] Add support for -XX:+ExitOnOutOfMemoryError. #4520

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions substratevm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ This changelog summarizes major changes to GraalVM Native Image.

## Version 22.2.0
* (GR-20653) Re-enable the usage of all CPU features for JIT compilation on AMD64.
* (GR-38413) Add support for -XX:+ExitOnOutOfMemoryError.

## Version 22.1.0
* (GR-36568) Add "Quick build" mode, enabled through option `-Ob`, for quicker native image builds.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

import java.lang.ref.Reference;

import com.oracle.svm.core.heap.OutOfMemoryUtil;
import com.oracle.svm.core.heap.VMOperationInfos;
import com.oracle.svm.core.jfr.JfrTicks;
import org.graalvm.compiler.api.replacements.Fold;
Expand Down Expand Up @@ -96,8 +97,6 @@
* Garbage collector (incremental or complete) for {@link HeapImpl}.
*/
public final class GCImpl implements GC {
private static final OutOfMemoryError OUT_OF_MEMORY_ERROR = new OutOfMemoryError("Garbage-collected heap size exceeded.");

private final GreyToBlackObjRefVisitor greyToBlackObjRefVisitor = new GreyToBlackObjRefVisitor();
private final GreyToBlackObjectVisitor greyToBlackObjectVisitor = new GreyToBlackObjectVisitor(greyToBlackObjRefVisitor);
private final BlackenImageHeapRootsVisitor blackenImageHeapRootsVisitor = new BlackenImageHeapRootsVisitor();
Expand Down Expand Up @@ -146,7 +145,7 @@ public void maybeCollectOnAllocation() {
outOfMemory = collectWithoutAllocating(GenScavengeGCCause.OnAllocation, false);
}
if (outOfMemory) {
throw OUT_OF_MEMORY_ERROR;
throw OutOfMemoryUtil.heapSizeExceeded();
}
}

Expand All @@ -161,7 +160,7 @@ private void collect(GCCause cause, boolean forceFullGC) {
if (!hasNeverCollectPolicy()) {
boolean outOfMemory = collectWithoutAllocating(cause, forceFullGC);
if (outOfMemory) {
throw OUT_OF_MEMORY_ERROR;
throw OutOfMemoryUtil.heapSizeExceeded();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/
package com.oracle.svm.core.genscavenge;

import com.oracle.svm.core.heap.OutOfMemoryUtil;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.word.Pointer;
Expand Down Expand Up @@ -110,7 +111,7 @@ AlignedHeader produceAlignedChunk() {
noteFirstAllocationTime();
result = (AlignedHeader) CommittedMemoryProvider.get().allocateAlignedChunk(chunkSize, HeapParameters.getAlignedHeapChunkAlignment());
if (result.isNull()) {
throw ALIGNED_OUT_OF_MEMORY_ERROR;
throw OutOfMemoryUtil.reportOutOfMemoryError(ALIGNED_OUT_OF_MEMORY_ERROR);
}
log().string(" new chunk: ").zhex(result).newline();

Expand Down Expand Up @@ -272,7 +273,7 @@ UnalignedHeader produceUnalignedChunk(UnsignedWord objectSize) {
noteFirstAllocationTime();
UnalignedHeader result = (UnalignedHeader) CommittedMemoryProvider.get().allocateUnalignedChunk(chunkSize);
if (result.isNull()) {
throw UNALIGNED_OUT_OF_MEMORY_ERROR;
throw OutOfMemoryUtil.reportOutOfMemoryError(UNALIGNED_OUT_OF_MEMORY_ERROR);
}

UnalignedHeapChunk.initialize(result, chunkSize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import com.oracle.svm.core.genscavenge.graal.nodes.FormatArrayNode;
import com.oracle.svm.core.genscavenge.graal.nodes.FormatObjectNode;
import com.oracle.svm.core.graal.snippets.DeoptTester;
import com.oracle.svm.core.heap.OutOfMemoryUtil;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.hub.LayoutEncoding;
import com.oracle.svm.core.log.Log;
Expand Down Expand Up @@ -241,7 +242,8 @@ private static Object slowPathNewArray(Word objectHeader, int length, int fillSt
*/
GCImpl.getPolicy().ensureSizeParametersInitialized();
if (size.aboveOrEqual(GCImpl.getPolicy().getMaximumHeapSize())) {
throw new OutOfMemoryError("Array allocation too large.");
OutOfMemoryError outOfMemoryError = new OutOfMemoryError("Array allocation too large.");
throw OutOfMemoryUtil.reportOutOfMemoryError(outOfMemoryError);
}

Object result = slowPathNewArrayWithoutAllocating(hub, length, size, fillStartOffset);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
* Garbage collection-specific options that are supported by all garbage collectors.
*/
public class SubstrateGCOptions {
@Option(help = "Print more information about the heap before and after each collection", type = OptionType.Expert)//
@Option(help = "Print more information about the heap before and after each collection.", type = OptionType.Expert)//
public static final RuntimeOptionKey<Boolean> VerboseGC = new GCRuntimeOptionKey<>(false);

@Option(help = "Determines if references from runtime-compiled code to Java heap objects should be treated as strong or weak.", type = OptionType.Debug)//
Expand All @@ -52,9 +52,12 @@ public class SubstrateGCOptions {
@Option(help = "Ignore calls to System.gc()", type = OptionType.Expert)//
public static final RuntimeOptionKey<Boolean> DisableExplicitGC = new GCRuntimeOptionKey<>(false);

@Option(help = "Print summary GC information after each collection", type = OptionType.Expert)//
@Option(help = "Print summary GC information after each collection.", type = OptionType.Expert)//
public static final RuntimeOptionKey<Boolean> PrintGC = new GCRuntimeOptionKey<>(false);

@Option(help = "Exit on the first occurrence of an out-of-memory error that is thrown because the Java heap is out of memory.", type = OptionType.Expert)//
public static final RuntimeOptionKey<Boolean> ExitOnOutOfMemoryError = new GCRuntimeOptionKey<>(false);

@Option(help = "The minimum heap size at run-time, in bytes.", type = OptionType.User)//
public static final RuntimeOptionKey<Long> MinHeapSize = new ImmutableGCRuntimeOptionKey<>(0L) {
@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2022, 2022, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.oracle.svm.core.heap;

import com.oracle.svm.core.SubstrateGCOptions;
import com.oracle.svm.core.annotate.RestrictHeapAccess;
import com.oracle.svm.core.headers.LibC;
import com.oracle.svm.core.jdk.JDKUtils;
import com.oracle.svm.core.log.Log;
import com.oracle.svm.core.util.VMError;

public class OutOfMemoryUtil {
private static final OutOfMemoryError OUT_OF_MEMORY_ERROR = new OutOfMemoryError("Garbage-collected heap size exceeded.");

@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Can't allocate when out of memory.")
public static OutOfMemoryError heapSizeExceeded() {
return reportOutOfMemoryError(OUT_OF_MEMORY_ERROR);
}

@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Can't allocate while out of memory.")
public static OutOfMemoryError reportOutOfMemoryError(OutOfMemoryError error) {
if (SubstrateGCOptions.ExitOnOutOfMemoryError.getValue()) {
if (LibC.isSupported()) {
Log.log().string("Terminating due to java.lang.OutOfMemoryError: ").string(JDKUtils.getRawMessage(error)).newline();
LibC.exit(3);
} else {
VMError.shouldNotReachHere("ExitOnOutOfMemoryError can only be used if the LibC support is present.");
}
}
throw error;
}
}