jvm-直接内存中的那点事【详细】

本文探讨了Java直接内存的使用场景、GC机制,以及直接内存与非直接内存的区别。重点讲解了NIO如何通过DirectByteBuffer高效地分配堆外内存,以及如何避免因内存溢出导致的OutOfMemoryError。
摘要由CSDN通过智能技术生成

直接内存概述

  • 直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。但是这部分内存也被频繁使用,而且也可能导致OutOfMemoryError一场出现,
  • 在jdk1.4中新加入了NIO(New Input/Output)类,引入了一种基于信道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer 对象作为这块内存的引用进行操作,这样能在一些场景中显著提高性能,因为避免了在Java堆和native堆中来回复制数据
  • 显然本机直接内存的分配不会受到Java堆大小的限制,但是,既然是内存,肯定还是会受到本机总内存(包括RAM以及SWAP区或者分页文件)大小及处理器寻址空间的限制,服务器管理员在配置虚拟机参数是,会根据实际内存设置-Xmx等参数信息,但经常忽略直接内存,使得各个内存区域总和大于物理内存限制(包括物理的和操作系统级的限制),从而导致动态扩展出现OutOfMemoryError异常

直接 内存GC

jvm中的直接内存,存在堆内存中其实就是DirectByteBuffer类,它本身很小,真的内存是在堆的外卖呢,这里是映射关系。

每次申请直接内存,都先看看是否已经达到了限定最大的直接内存大小(可以用 -XX:MaxDirectMemorySize设定),如果超出了,就会执行System.gc(),在GC的时候触发Stop-The-World ,因为是直接内存回收,时间会比较长,如果没有回收成功直接内存,并且还是超过直接内存的限额,就会抛出OOM

DirectByteBuffer熬过了几次young gc之后,会进入老年代。当老年代满了之后,会触发Full GC。

因为本身很小,很难占满老年代,因此基本不会触发Full GC,带来的后果是大量堆外内存一直占着不放,无法进行内存回收。还有最后一个办法,就是依靠申请额度超限时触发的system.gc(),但是它会中断进程100ms,如果在这100ms的之间,系统未完成GC,仍会抛出OOM。

直接内存和非直接内存差异

直接 非直接内存的概念与NIO有非常大的关联;

在NIO之前,java.io 的方式是:
	 磁盘IO --> 直接内存[系统内核态] -->   非直接(堆)内存[用户态]  -->  直接内存[系统内核态] --> 磁盘IO

而NIO中,对文件的读写不再跟堆内存关联
	磁盘IO --> 系统直接内存 --> 磁盘IO

读写文件时可以直接申请堆外内存。
请添加图片描述

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

little Chen1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值