暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

关于Direct buffer memory溢出

原创 刘韬 云和恩墨 2022-05-23
4523

Direct buffer memory溢出分析

描述

Oracle jdk的Direct Byte Buffers由专属的一块内存区域管理控制,所有 Direct Byte Buffer 大小的总和不能超过限制。达到限制后,只有在释放足够的旧缓冲区以提供足够的空间来分配新缓冲区时,才能分配新的直接字节缓冲区。如果这一块内存区域配置不当就会影响到系统的正常运行。

分析

  1. 查看发现问题时的日志

Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory

at java.nio.Bits.reserveMemory(Bits.java:694)

at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)

at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)

  1. 从上面日志可以发现在系统运行过程中出现了内存溢出

  1. 这种溢出跟heap 内存溢出不同,并不会产生heapdump文件
  2. 目前的虚拟机参数配置为 -Xmx4096m

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/heap

  1. DirectBuffers requested by the method called java.nio.ByteBuffer.allocateDirect() are allocated in C-Heap and not in Java heap,默认分配在c堆,不在heap区域(JVM Error Message "java.lang.OutOfMemoryError: Direct buffer memory"

(Doc ID 1493911.1) )

  1. DirectBuffers 默认大小由Runtime.getRuntime.maxMemory()

决定,(Doc ID 1493911.1)

解决

通过上面的分析可以找到解决措施,

  1. 如果没有直接指定DirectBuffers内存大小,这块内存受heap堆分配决定,因为Runtime.getRuntime.maxMemory()由jvm参数 -Xmx决定
  2. 举个例子如果-Xmx4g,那么DirectBuffers大小在3.7g上下
  3. 根据官方的解释如下

-XX:MaxDirectMemorySize=size

Sets the maximum total size (in bytes) of the New I/O (the java.nio package) direct-buffer allocations. Append the letter k or K to indicate kilobytes, m or M to indicate megabytes, g or G to indicate gigabytes. By default, the size is set to 0, meaning that the JVM chooses the size for NIO direct-buffer allocations automatically.

The following examples illustrate how to set the NIO size to 1024 KB in different units:

-XX:MaxDirectMemorySize=1m

-XX:MaxDirectMemorySize=1024k

-XX:MaxDirectMemorySize=1048576

通过此参数可以分配更多的内存以保证需要

  1. 测试验证:直接配置为1g后,即使-Xmx设置为256m,也可以分配500m的direct buffer

In the following example we set the MaxDirectMemorySize to 1 GB which is enough to allocate a DirectBuffer of 500 MB size. The OutOfMemory error does not occur anymore even if we set -Xmx to 256 MB only.

Example:

$ java -XX:MaxDirectMemorySize=1g -Xmx256m <APP_NAME>
238616576

$ cat <APP_NAME>.java
public class Dibu {
    public static void main(String[] args) {
        java.nio.ByteBuffer.allocateDirect(500*1024*1024); // 500 MB
        System.out.println(Runtime.getRuntime().maxMemory());
    }
}

  1. 更新后重启虚拟机生效
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论