Direct Buffer Used Despite Parameters Indicating Not To
See original GitHub issueExpected behavior
If -Dio.netty.allocator.numDirectArenas=0
and -Dio.netty.noPreferDirect=true
, that Direct Buffers are not used when a Heap Buffer is possible.
Actual behavior
Instead, Direct Buffers are always used as shown in this Stacktrace:
16:37:49.059 [nioEventLoopGroup-3-4] WARN DefaultChannelPipeline - An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
io.netty.util.internal.OutOfDirectMemoryError: failed to allocate 480 byte(s) of direct memory (used: 1073741767, max: 1073741824)
at io.netty.util.internal.PlatformDependent.incrementMemoryCounter(PlatformDependent.java:535)
at io.netty.util.internal.PlatformDependent.allocateDirectNoCleaner(PlatformDependent.java:489)
at io.netty.buffer.UnpooledUnsafeNoCleanerDirectByteBuf.allocateDirect(UnpooledUnsafeNoCleanerDirectByteBuf.java:30)
at io.netty.buffer.UnpooledUnsafeDirectByteBuf.<init>(UnpooledUnsafeDirectByteBuf.java:67)
at io.netty.buffer.UnpooledUnsafeNoCleanerDirectByteBuf.<init>(UnpooledUnsafeNoCleanerDirectByteBuf.java:25)
at io.netty.buffer.UnsafeByteBufUtil.newUnsafeDirectByteBuf(UnsafeByteBufUtil.java:410)
at io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:336)
at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:183)
at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:174)
at io.netty.buffer.AbstractByteBufAllocator.ioBuffer(AbstractByteBufAllocator.java:135)
at io.netty.channel.AdaptiveRecvByteBufAllocator$HandleImpl.allocate(AdaptiveRecvByteBufAllocator.java:104)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:117)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:646)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:581)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:498)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:460)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:131)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
Why? See io.netty.buffer.AbstractByteBufAllocator.ioBuffer(AbstractByteBufAllocator.java:135)
aka https://github.com/netty/netty/blob/2dc686ded17d8123118921ac6d36aea30cdce267/buffer/src/main/java/io/netty/buffer/AbstractByteBufAllocator.java#L128-L150
@Override
public ByteBuf ioBuffer() {
if (PlatformDependent.hasUnsafe() || isDirectBufferPooled()) {
return directBuffer(DEFAULT_INITIAL_CAPACITY);
}
return heapBuffer(DEFAULT_INITIAL_CAPACITY);
}
From the above, if hasUnsafe
evaluates to true, directBuffer() is invoked vs. heapBuffer().
The only workaround is to provide -Dio.netty.noUnsafe=true
in addition to the aforementioned parameters.
Steps to reproduce
N/A
Minimal yet complete reproducer code (or URL to code)
N/A
Netty version
Latest
JVM version (e.g. java -version
)
openjdk version “1.8.0_202”
OS version (e.g. uname -a
)
Ubuntu 16.04
Issue Analytics
- State:
- Created 4 years ago
- Comments:6 (4 by maintainers)
Top Results From Across the Web
How to garbage collect a direct buffer in Java - Stack Overflow
A direct byte buffer may be created by invoking the allocateDirect factory method of this class. The buffers returned by this method typically ......
Read more >Troubleshooting OutOfMemoryError: Direct buffer memory
OutOfMemoryError: Direct buffer memory Error will be throw. A good runtime indicator of a growing Direct Buffers allocation is the size of Non- ......
Read more >Direct Buffer - Aeron Cookbook
DirectBuffer implementations offer methods to read and write both individual bytes along with regions of bytes. Char data is also supported, although it...
Read more >OBJ53-J. Do not use direct buffers for short-lived, infrequently ...
Direct buffers are also outside the scope of Java's garbage collector; consequently, injudicious use of direct buffers can cause memory leaks.
Read more >Buffers | Calbiochem
Table 1: pKa Values for Commonly Used Biological Buffers and Buffer Constituents. Product. Cat. No. M.W.. pKa at. 20°C. BES, ULTROL® Grade.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Thanks for the quick replies @ejona86 @carl-mastrangelo @normanmaurer , I really appreciate it.
(Note: I’m going to be very explicit with flags and such so that other people with the same issue can find it in a Google search)
My attempt to avoid direct buffers arose out of trying to triage
OutOfDirectMemoryError
s being thrown repeatedly in a high throughput application. Turning on-Dio.netty.leakDetection.level=paranoid
returned nothing, and limiting-XX:MaxDirectMemorySize
didn’t prove fruitful either. Inspecting direct memory is fairly difficult in our deployment environment, so I was looking to have all allocations heap-based when possible, that way an OutOfMemoryError would trigger a Heap Dump via-XX:+HeapDumpOnOutOfMemoryError
, and then I could begin to investigate what was “leaking” or dominating.The following three parameters were enough to cause a Heap Dump vs. OutOfDirectMemoryError:
-Dio.netty.allocator.numDirectArenas=0
,-Dio.netty.noPreferDirect=true
, and-Dio.netty.noUnsafe=true
. After analyzing the Heap Dump, I was able to determine that reducing-Dio.netty.allocator.maxOrder
to 3 for our Heap size (~2GB) was the appropriate solution, as that in turn reduced the chunkSize (and other artifacts) to a more reasonable limit.Long story short: Having the option to use heap memory vs. direct memory proved very useful in identifying a “leak” (in this case, it wasn’t really a leak, just too aggressive of an allocation strategy) in a deployment environment that doesn’t permit direct access to the Box/VM/container.
Fair enough. Maybe a small enhancement could be made to the documentation or Javadoc indicating that even if
-Dio.netty.allocator.numDirectArenas=0
and-Dio.netty.noPreferDirect=true
, direct memory will still be used (and why).Good question. Netty in this case is being used by a third party library that we have no control over. Is there a
-Dio.netty
flag that can be set to indicate the Class desired?I don’t think those configuration options imply “no direct buffers.” They mean “no pooling for direct buffers” and “given a choice between direct and heap, whether direct should be used.”
I think “don’t use any direct buffers” is more of a feature request. Right now any code that calls alloc.directBuffer() should get a direct buffer. And it seems fair that ioBuffer also is a direct buffer, given how memory works in Java. So I don’t know if even that makes sense.
@amcrn, can you explain why direct memory is off-limits for you?