Ewen Seong 2023-06-05 10:35 采纳率: 0%
浏览 57
已结题

JVM直接内存释放问题

最近发现个问题, 有点困惑,请指点:
Java程序使用 ByteBuffer.allocateDirect(1024 * 1024)分配500M直接内存(循环500次),在top -p或者在proc的VmRSS指标中 显示内存被占用(约500M的上涨);
反复继续分配-直到达到直接内存上限,抛出直接内存的OOM异常;此时VmRSS内存指标已达到一个峰值;
手动触发Full-GC来释放掉直接内存,此时VmRSS没有明显的下降(波动10M以内),而VisualVM通过Buffer Pool插件跟踪的直接内存下降了500M;
再次使用ByteBuffer.allocateDirect(500* 1024 * 1024) 分配成功,VmRSS和VisualVM的Buffer Pool同时上涨500M;不断进行(clear -> allocate),VmRSS会不断往上提升,远远超过直接内存上限

逻辑代码如下所示:

 private static final List<ByteBuffer> BUFFER_LIST = new ArrayList<>();

  private void allocate(int n) {
        for (int i = 0; i < n; i++) {
            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024 * 1024);
            BUFFER_LIST.add(byteBuffer);
        }
    }

  private void clear() {
        BUFFER_LIST.clear();
        System.gc();
    }
  • 写回答

9条回答 默认 最新

  • 6~1!阿白 2023-06-05 13:10
    关注
    获得1.20元问题酬金

    这是因为直接内存的释放与 JVM GC 不完全相同。ByteBuffer.allocateDirect() 分配的内存空间是由操作系统管理的,而不是由 JVM 的 GC 管理的。当你持有 Direct Buffers 时,JVM 的垃圾收集器并不会回收它们,因此在 JVM 进程的 VMRSS 中,反复申请时会出现 VMRSS 一直上涨的情况。

    另外一点需要注意的是,手动触发 System.gc() 并不能保证立即释放所有 Direct Buffers 占用的空间,因为 JVM 并不能准确知道 Direct Buffers 到底是否被使用中,因此可能需要等待更长的时间才能真正回收这些空间。

    如果需要释放已分配的直接内存空间,在 Java NIO 库中提供了 ByteBuffer 类的 clear() 方法,该方法清空 Direct Buffer,并将其标记为空闲状态,让 Direct Buffers 归还给系统进行回收。因此,建议在适当的时候调用 ByteBuffer.clear() 方法释放 Direct Buffers 内存空间,而不是依赖于手动触发垃圾回收。

    评论

报告相同问题?

问题事件

  • 系统已结题 6月13日
  • 创建了问题 6月5日

悬赏问题

  • ¥15 C++ yoloV5改写遇到的问题
  • ¥20 win11修改中文用户名路径
  • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入
  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
  • ¥70 PlayWright在Java上连接CDP关联本地Chrome启动失败,貌似是Windows端口转发问题
  • ¥15 帮我写一个c++工程
  • ¥30 Eclipse官网打不开,官网首页进不去,显示无法访问此页面,求解决方法
  • ¥15 关于smbclient 库的使用
  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?