Memory and Workspaces
Off-heap memory management, JVM configuration, workspace modes, and troubleshooting memory issues in ND4J and DL4J
Understanding how memory works in the DL4J ecosystem is essential for avoiding out-of-memory errors and getting optimal performance. ND4J uses a fundamentally different memory model than typical Java applications.
Off-Heap Memory
All INDArray data is stored off-heap — outside the Java Virtual Machine's managed heap. The JVM holds only a small pointer object; the actual tensor data lives in native memory managed by JavaCPP.
This design has several benefits:
BLAS interoperability: Native memory can be passed directly to OpenBLAS, MKL, and cuBLAS without copying
No 2^31 element limit: Java arrays are limited to ~2.1 billion elements due to int indexing; off-heap has no such limit
Reduced GC pressure: Large arrays don't contribute to GC pause times
GPU compatibility: CUDA memory is inherently off-heap
The downside: you must configure both JVM heap memory and off-heap memory.
JVM Memory Configuration
A typical launch configuration:
java -Xms2G -Xmx4G \
-Dorg.bytedeco.javacpp.maxbytes=8G \
-Dorg.bytedeco.javacpp.maxphysicalbytes=12G \
-jar your-app.jarFlags Explained
-Xms
Initial JVM heap size
Set equal to -Xmx to avoid resizing
-Xmx
Maximum JVM heap size
Keep small relative to total RAM (2-4G usually sufficient)
-Dorg.bytedeco.javacpp.maxbytes
Maximum off-heap memory for ND4J
Set based on your model and data size
-Dorg.bytedeco.javacpp.maxphysicalbytes
Maximum total physical memory (heap + off-heap)
Set to ~80% of available RAM
Key Rules
Keep
-Xmxsmall. The JVM heap holds configuration objects, iterators, and string data — not tensor data. 2-4G is usually enough.Allocate most memory off-heap. Set
maxbytesto several times-Xmx.Leave room for the OS. Don't allocate 100% of system RAM. Leave at least 1-2G for the OS and other processes.
For GPU:
maxbytescontrols both CPU off-heap and GPU memory allocation. On GPU machines, set this based on your GPU VRAM.
Example Configurations
Development machine (16G RAM, CPU):
Training server (64G RAM, GPU with 16G VRAM):
Small model / embedded (4G RAM):
Workspaces
Workspaces are ND4J's mechanism for reusing memory allocations across iterations of a loop. Instead of allocating and deallocating native memory on every training iteration (which is slow), workspaces pre-allocate a block of memory and recycle it.
How Workspaces Work
First iteration: workspace allocates memory as needed, tracking the total
Subsequent iterations: workspace reuses the same memory block, overwriting previous values
No allocation/deallocation overhead after the first iteration
This is especially effective for neural network training, where each iteration uses roughly the same amount of memory.
WorkspaceMode
WorkspaceMode is at org.deeplearning4j.nn.conf.WorkspaceMode:
ENABLED
Default. Workspaces active for both training and inference. Best performance.
NONE
Workspaces disabled. Useful for debugging memory issues.
SINGLE
Deprecated. Use ENABLED instead.
SEPARATE
Deprecated. Use ENABLED instead.
Configure via the builder:
To disable workspaces for debugging:
Manual Workspace Usage
For custom code that needs workspace control:
Scope Panic: Leaked and Outdated Workspace Pointers
When using workspaces (including the default workspace mode in DL4J), you may encounter exceptions like:
or:
What These Mean
Leaked pointer: An
INDArrayallocated inside a workspace is being used after the workspace was closed. The memory it points to has been reclaimed.Outdated pointer: An
INDArrayfrom a previous iteration of a workspace loop is being used in the current iteration. The memory has been overwritten.
Leaked Pointer Example
Outdated Pointer Example
Fixes
1. Detach from workspace — copies the array to independent off-heap memory:
2. Allocate outside workspace — temporarily disable workspace:
3. Migrate to parent workspace — moves the array to an enclosing workspace:
If You Didn't Write Custom Code
If you encounter scope panic using standard DL4J APIs (no custom layers, no custom data pipeline), it is likely a bug. Workarounds:
Garbage Collection Tuning
ND4J's off-heap memory is eventually freed by Java's garbage collector when the INDArray pointer objects are collected. For tight loops without workspaces, GC may not run frequently enough, causing off-heap memory to grow.
Periodic GC
ND4J can trigger periodic GC calls:
Manual GC
For inference workloads with variable batch sizes:
Monitoring Memory Usage
Common Memory Issues and Solutions
OutOfMemoryError: Java heap space
JVM heap too small
Increase -Xmx
OutOfMemoryError: Direct buffer memory
Off-heap limit reached
Increase maxbytes
Gradual memory increase during training
GC not collecting INDArray pointers
Enable periodic GC or use workspaces
ND4JIllegalStateException: leaked workspace
Array used outside its workspace
Use .detach() or scopeOutOfWorkspaces()
ND4JIllegalStateException: outdated workspace
Array from previous iteration
Use .detach() before storing across iterations
OOM on GPU
VRAM exhausted
Reduce batch size, reduce model size, or use mixed precision
Slow first epoch, fast subsequent
Normal — workspace warm-up
Expected behavior; first iteration allocates, subsequent reuse
Last updated
Was this helpful?