OutOfMemoryError on my BF interpreter

Boris Spasojevic boris.spasojevic at oracle.com
Wed May 2 09:18:51 UTC 2018

Hey Christian,

This could very well be caused by the calls to System.out.print and 

Could you please try wrapping calls to such external methods and adding 
a @TruffleBoundary annotation? The end goal would be something like:

public class PrintDataNode extends BFNode {
     private final FrameSlot ptr;
     private final FrameSlot data;

     public PrintDataNode(FrameSlot ptr, FrameSlot data) {
         this.ptr = ptr;
         this.data = data;

     void print(char c) {

     public void execute(VirtualFrame frame) {
         try {
             print((char) ((byte[]) 
         } catch (FrameSlotTypeException e) {

You can see a similar pattern being used in Simple language 

Hope that helps!

On 05/02/2018 10:46 AM, Cristian Esquivias wrote:
> Hi Josef,
> Thanks for the context. I'll try to build the GraalVM and see if it
> solves the issue.
> After reading the bug report, here's a little bit more info that I hope helps:
> * The report says the SSA register allocator could be the problem on
> "large inputs". I'm not sure what constitutes a large input, but my
> mandelbrot script creates around 11,000 nodes in total. That's
> probably not a huge amount, but they're all within one function since
> BF doesn't have the concept of functions. That's probably a little
> more unusual.
> * My interpreter doesn't put pressure on the heap. After an initial
> allocation of a 1,000-10,000 size int array no more allocations are
> done for the rest of a script's life. This is proven out by jvisualvm.
> The heap stays flat throughout most of the run and only spikes right
> before the OOME occurs.
> * There are very few (essentially no) opportunities for adding
> TruffleBoundary annotations since nearly all my nodes' execute methods
> are one line that do little more than fetch an item out of my array
> and inc/dec the value. The only calls out to external methods are
> calls to VirtualFrame.get [1]/set [2] some variable values, calls to
> stdout's print method [3] and stdin's read method [4]. A truffle
> expert's help would definitely be appreciated here since I'm just
> making an educated guess.
> * The OOME occurs inside a loop node. Could this OOME be caused by
> loop unrolling [5]?
> Thanks,
> Cristian
> [1]: https://github.com/cesquivias/bf-graal/blob/master/lang/src/main/java/cesquivias/bf/DecDataNode.java
> [2]: https://github.com/cesquivias/bf-graal/blob/master/lang/src/main/java/cesquivias/bf/DecPointerNode.java
> [3]: https://github.com/cesquivias/bf-graal/blob/master/lang/src/main/java/cesquivias/bf/PrintDataNode.java
> [4]: https://github.com/cesquivias/bf-graal/blob/master/lang/src/main/java/cesquivias/bf/ReadDataNode.java
> [5]: https://github.com/cesquivias/bf-graal/blob/master/lang/src/main/java/cesquivias/bf/BFRepeatingNode.java
> On Wed, May 2, 2018 at 12:37 AM, Josef Eisl <josef.eisl at jku.at> wrote:
>> Hi Cristian!
>> Thanks for your report. We have very recently merged a change to
>> mitigate the OOME in this part of linear scan [1]. Unfortunately this
>> was after the release so it is not included in 1.0.0 RC1. You would need
>> to build your own GraalVM from source to see if the change helps.
>> That said, the root cause of the OOME is usually a huge compilation unit
>> thrown into the compiler. For more details, see also the discussion on
>> the OpenJDK bug tracker [2].
>> The reasons for big compilation units can me manifold. In case of
>> Truffle, the issues can often be solved by adding TruffleBoundaries [3],
>> i.e., instructing the compiler not to inline specified methods into the
>> truffle graph. Maybe a Truffle expert can give you more hints on that.
>> Hope that helps,
>> Josef
>> [1]:
>> https://github.com/oracle/graal/commit/c0a15c562daa0338f61a6e7c22476cf145af5a66
>> [2]: https://bugs.openjdk.java.net/browse/JDK-8199890
>> [3]:
>> http://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/CompilerDirectives.TruffleBoundary.html
>> On 01/05/18 08:24, Cristian Esquivias wrote:
>>> With the release of 1.0.0-RC1 I thought I'd come back and see how
>>> Graal is doing. Great job; Graal is really starting to look like the
>>> platform everyone should pay attention to.
>>> To get back into it, I built a Brainf*ck interpreter with Truffle
>>> (https://github.com/cesquivias/bf-graal). I modeled it after
>>> simplelanguage so it should be easy to build and run.
>>> While running the mandelbrot program, about halfway through the
>>> program, the VM starts throwing OutOfMemoryError exceptions (one
>>> pasted below). It created a zip file under dumps/ but it contains a
>>> .bgv file I don't what to do with and a log file that just contains
>>> the stacktrace.
>>> I ran jvisualvm and took a heap dump. There are ~200k long[] objects
>>> alone created by graal taking up ~50% of the memory. Digging through
>>> the references it seems to be created/retained in
>>> org.graalvm.compiler.lir.alloc.lsra.LinearScanLifetimeAnalysisPhase$$Lambda$48#1
>>> [GC root - Java frame]
>>> I'd provide some file from jvisualvm but the save button is grayed
>>> out. I hope this is enough info. My interpreter is up on GitHub so
>>> feel free to test it out.
>>> I tested this both on the community & enterprise edition on Ubuntu
>>> 18.04 in VirtualBox.
>>> - Cristian
>>> Thread[TruffleCompilerThread-12,10,main]: Compilation of
>>> BFRepeatingNode at 222b298d<OSR> failed: java.lang.OutOfMemoryError: Java
>>> heap space
>>> at org.graalvm.compiler.lir.util.IndexedValueMap.<init>(IndexedValueMap.java:55)
>>> at org.graalvm.compiler.lir.dfa.RegStackValueSet.<init>(RegStackValueSet.java:62)
>>> at org.graalvm.compiler.lir.dfa.RegStackValueSet.copy(RegStackValueSet.java:70)
>>> at org.graalvm.compiler.lir.dfa.RegStackValueSet.copy(RegStackValueSet.java:46)
>>> at org.graalvm.compiler.lir.dfa.LocationMarker.processBlock(LocationMarker.java:107)
>>> at org.graalvm.compiler.lir.dfa.LocationMarker.build(LocationMarker.java:81)
>>> at org.graalvm.compiler.lir.dfa.LocationMarkerPhase.run(LocationMarkerPhase.java:51)
>>> at org.graalvm.compiler.lir.dfa.LocationMarkerPhase.run(LocationMarkerPhase.java:47)
>>> at org.graalvm.compiler.lir.phases.LIRPhase.apply(LIRPhase.java:115)
>>> at org.graalvm.compiler.lir.phases.LIRPhase.apply(LIRPhase.java:107)
>>> at org.graalvm.compiler.lir.phases.LIRPhaseSuite.run(LIRPhaseSuite.java:96)
>>> at org.graalvm.compiler.lir.phases.LIRPhase.apply(LIRPhase.java:115)
>>> at org.graalvm.compiler.lir.phases.LIRPhase.apply(LIRPhase.java:107)
>>> at org.graalvm.compiler.core.GraalCompiler.emitLowLevel(GraalCompiler.java:367)
>>> at org.graalvm.compiler.core.GraalCompiler.emitLIR0(GraalCompiler.java:336)
>>> at org.graalvm.compiler.core.GraalCompiler.emitLIR(GraalCompiler.java:295)
>>> at org.graalvm.compiler.core.GraalCompiler.emitBackEnd(GraalCompiler.java:275)
>>> at org.graalvm.compiler.core.GraalCompiler.compile(GraalCompiler.java:175)
>>> at org.graalvm.compiler.core.GraalCompiler.compileGraph(GraalCompiler.java:160)
>>> at org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl.compilePEGraph(TruffleCompilerImpl.java:445)
>>> at org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl.compileAST(TruffleCompilerImpl.java:391)
>>> at org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl$TruffleCompilationWrapper.performCompilation(TruffleCompilerImpl.java:544)
>>> at org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl$TruffleCompilationWrapper.performCompilation(TruffleCompilerImpl.java:493)
>>> at org.graalvm.compiler.core.CompilationWrapper.run(CompilationWrapper.java:167)
>>> at org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl.doCompile(TruffleCompilerImpl.java:222)
>>> at org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime.doCompile(GraalTruffleRuntime.java:679)
>>> at org.graalvm.compiler.truffle.runtime.GraalTruffleRuntime$1.run(GraalTruffleRuntime.java:745)
>>> at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
>>> at java.util.concurrent.FutureTask.run(FutureTask.java:266)
>>> at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
>>> at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
>>> at java.lang.Thread.run(Thread.java:748)
>>> To disable compilation failure notifications, set
>>> CompilationFailureAction to Silent (e.g.,
>>> -Dgraal.CompilationFailureAction=Silent).
>>> To print a message for a compilation failure without retrying the
>>> compilation, set CompilationFailureAction to Print (e.g.,
>>> -Dgraal.CompilationFailureAction=Print).
>>> Retrying compilation of BFRepeatingNode at 222b298d<OSR>

More information about the graal-dev mailing list