[SOLVED] "java.lang.OutOfMemoryError: Direct buffer memory" when creating a lot of Box instances

I am trying to create a Minecraft like program. I am running out of Direct Memory when I try to increase the size of the world.
The program uses an instance of the Box class for each “cube”. I am finding that e.g. 1 million boxes needs around 1 gigabyte of Direct Memory. That works out to around 1000 bytes per Box.

Note that this is Direct Memory (these are DirectFloatBuffer instances as far as I can tell). JVM heap usage is fine.

Does this sound right?

The following code example illustrates the issue I am getting. Run this with a heap size of 2GB to reproduce the behaviour.

public static void main(String[] args) {
    // Run with -Xmx2048m
    int rows = 2000;
    List<Spatial> spatials=new ArrayList<>();
    for(int i=0;i<rows;i++){
        if(i%100==0)
            System.out.println("Created "+i+" rows");
        Node rowNode = new Node("parent");
        for(int j=0;j<rows;j++){
            Box box = new Box(1, 1, 1);
            Geometry geometry = new Geometry("geometry", box);
            rowNode.attachChild(geometry);
        }
        Spatial optimised = GeometryBatchFactory.optimize(rowNode);
        spatials.add(optimised);
    }
}

When I run this I get an exception

Created 1100 nodes
Exception in thread “main” java.lang.OutOfMemoryError: Direct buffer memory

Note that I am using GeometryBatchFactory.optimize() to reduce heap usage enough to show the problem with Direct Memory. If I just create Box instances, the direct memory usage is the same, but the program runs out of heap before it runs out of Direct memory.

I am using Oracle 1.8 JVM

Any thoughts?

or am I using the wrong approach altogether??

1 Like

Block worlds aren’t made out of boxes.

They are made out of meshes full of visible faces.

If you search the forum you will find a few thousand (million?) threads about this and at least two open source block engines that you can start from.

1 Like

If you are not set on rolling your own framework, you can use Blocks. You can checkout the page on the store or take a loot at the topic on the forum.
It will take care of the chunk management and mesh generation for you.

If not, you should rethink the way you are solving the issue. As paul said, a block world is not made of boxes. It’s made of different meshes that look like a lot of boxes stacked on top of each other.

It’s still odd that we need 1000 Byte for 8 vertices and a few indices.

Does cloning solve the issue? (Even though the others are correct as well)

Not sure where you get 8 vertexes for a JME Box.

6 sides * 4 vertices per side = 24 vertices.
24 verteices * 3 floats for position * 3 floats for normal * 2 floats for texture coordinates = 432 floats = 1728 bytes.

…and that’s not including the 6 shorts per side. 36 shorts * 2 = 72 bytes.

Or the overhead just for the object, etc…

So I guess a single Box mesh is taking up even more than 1000 bytes.

@remy_vd My worlds are based on a horizontal grid, but vertically I do not want to be constrained to a grid. I want to e.g. have a block that is 1x1x0.3 high. Does Blocks support this? The sample code I looked at implies blocks are all 1x1x1 in size.
Using Box objects allowed positioning and sizing the blocks to arbitrary positions.
This was one of the limitations of Minecraft I was hoping to avoid by writing my own application.
Even supporting blocks with heights less than 1 would be OK. For example, Minecraft has some blocks that are “slabs” that have a height of 0.5. I was using this but it didn’t look great.

Yes, but there is a very good reason that block world games do not do this. It’s effectively impossible to optimize beyond some simple “doesn’t matter” level stuff.

The reason block worlds work at all is because they are on a grid. You can get away with subdividing the grid in some cases but you will never get away from the grid.

I know a little bit about what I’m talking about here as this is my game-in-progress for some time: http://mythruna.com/

…and is the least blocky of all of the block-worlds that I’ve seen.

I was thinking 8 vertices and 6 faces. Like the “upper” quad and the “lower” quad, everything else could be with shared ones, couldn’t that work?
Either way I underestimated the normals, texture coordinates and indices etc.

Only if you were fine with each shared corner having the same normal, texture coordinate, etc. for the three faces that share it.

Cue tape: “A vertex is the unique combination of position and the other vertex attributes like normal, texture coordinate, etc.”

Specifically normals don’t make sense there, that’s true.

Edit: But when cloning a geometry the buffers should be shared, right?

Depends on how it was cloned… but then when you batch them together it doesn’t matter again (as in OP’s original code).

The default cube shaped block is indeed 1x1x1. But you can change this if you want. Using the Slab shape, you have a cube shape with a modifiable height.

By default, Blocks has a slab and a ‘double’ slab block. The first one has a height of 1/3, the second one a height of 2/3.

1 Like

I have now got it working well using the Blocks framework. The performance is good. I looked at the “ProceduralTerrain” example and worked from there.

Thank you to everyone who replied for all your help.

@remy_vd I will look into your Slab shape suggestion.

3 Likes

@remy_vd I ended up creating 20 different Slab blocks at 0.05 intervals, between 0.05 and 0.95 units high. It looks fantastic and performance doesn’t seem impacted, as far as I can tell. The terrain looks almost rounded now. Much better than I ever got from Minecraft!

2 Likes

Glad you got it working! Care to take some screenshots? I’m always curious of seeing how people are using Blocks. :slight_smile:

3 Likes

@remy_vd You asked for some screenshots. This is a terrain visualisation tool.

5 Likes