Java直接内存详解
来源:互联网 发布:芒果tv网络电视下载 编辑:程序博客网 时间:2024/06/11 01:48
JVM直接内存
前言
在做欢聚时代的校招题时遇到了一道选择题,选项D如下:
直接内存的分配不会受到Java堆大小的限制,所以不会抛OutOfMemoryError异常
由于对直接内存的概念不是很清晰,所以查询了相关资料,准备一篇博文总结一下
什么是直接内存
直接内存(Direct Memory)就是Java堆外内存
直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现,所以我们放到这里一起讲解。
在JDK 1.4中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。
显然,本机直接内存的分配不会受到Java堆大小的限制,但是,既然是内存,则肯定还是会受到本机总内存(包括RAM及SWAP区或者分页文件)的大小及处理器寻址空间的限制。服务器管理员配置虚拟机参数时,一般会根据实际内存设置-Xmx等参数信息,但经常会忽略掉直接内存,使得各个内存区域的总和大于物理内存限制(包括物理上的和操作系统级的限制),从而导致动态扩展时出现OutOfMemoryError异常。
NIO代码实例
NIO的Buffer提供一个可以直接访问系统物理内存的类——DirectBuffer。DirectBuffer类继承自ByteBuffer,但和普通的ByteBuffer不同。普通的ByteBuffer仍在JVM堆上分配内存,其最大内存受到最大堆内存的 限制。而DirectBuffer直接分配在物理内存中,并不占用堆空间。在访问普通的ByteBuffer时,系统总是会使用一个“内核缓冲区”进行操作。而DirectBuffer所处的位置,就相当于这个“内核缓冲区”。因此,使用DirectBuffer是一种更加接近内存底层的方法,所以它的速度比普通的ByteBuffer更快。
申请DirectBuffer代码如下: ByteBuffer.allocateDirect();
下面,使用DirectBuffer和普通的ByteBuffer进行一段性能测试。
DirectBuffer
long start = System.currentTimeMillis(); ByteBuffer buffer = ByteBuffer.allocateDirect(500);//分配500个字节的DirectBuffer for (int i = 0; i < 100000; i ++) { for (int j = 0; j < 99; j ++) { buffer.putInt(j); //向DirectBuffer写入数据 } buffer.flip(); for (int j = 0; j < 99; j ++) { buffer.get(); //从DirectBuffer中读取数据 } buffer.clear(); } System.out.println("DirectBuffer use : " + ( System.currentTimeMillis() - start ) + "ms");
执行结果: DirectBuffer use : 20ms
使用ByteBuffer:
long start = System.currentTimeMillis(); ByteBuffer buffer = ByteBuffer.allocate(500);//分配500个字节的ByteBuffer for (int i = 0; i < 100000; i ++) { for (int j = 0; j < 99; j ++) { buffer.putInt(j); //向DirectBuffer写入数据 } buffer.flip(); for (int j = 0; j < 99; j ++) { buffer.get(); //从DirectBuffer中读取数据 } buffer.clear(); } System.out.println("ByteBuffer use : " + ( System.currentTimeMillis() - start ) + "ms");
执行结果: ByteBuffer use : 33ms
以后两段测试代码分别使用了DirectBuffer和堆上的ByteBuffer,并进行了大量的读写访问。测试结果是DirectBuffer相对耗时20ms,而ByteBuffer相应耗时33ms.虽然都很快,但从比例上来说,DirectBuffer接近快了一倍。如果把外层的循环次数由10万改为100万,DirectBuffer use : 105ms,而ByteBuffer use : 225ms,快了一倍多。
不过,虽然有访问速度上的优势,但是在创建和销毁DirectBuffer的花费却远比ByteBuffer高。
for (int i = 0 ;i < 20000; i ++) { ByteBuffer b = ByteBuffer.allocateDirect(1000); } for (int i = 0 ;i < 20000; i ++) { ByteBuffer b = ByteBuffer.allocate(1000);}
上面的两个for循环表示分别请求每种类型的Buffer 20M,设置运行时参数-XX:MaxDirectMemorySize=10M -Xmx10M,运行以下代码,使用DirectBuffer的代码段相对耗时297ms,而使用ByteBuffer的相对耗时仅15ms。因此可知,频繁的创建和销毁DirectBuffer远远大于在堆上分配内存空间。
总结
DirectBuffer的读写操作比普通Buffer快,但它的创建、销毁却比普通Buffer慢。
- Java直接内存详解
- Java直接(堆外)内存使用详解
- Java直接(堆外)内存使用详解
- java 直接内存
- JAVA直接内存(堆外内存)
- Java直接内存与非直接内存性能测试
- Java直接内存读写的例子
- Java直接内存访问的技巧
- Java直接内存访问的技巧
- Java直接内存读写的例子
- Java直接内存分配和释放方式
- 直接内存
- java内存模型详解
- java内存模型详解
- Java内存机制详解
- Java内存模型详解
- java内存模型详解
- java内存模型详解
- 【HAOI2011】Problem b(莫比乌斯反演+分块儿)
- html css
- Tag 的常见用法
- c++Socket客户端 (vs2013)
- 大数据技术和应用
- Java直接内存详解
- mysql_备份与恢复
- 推荐:使用 Istio Service Mesh 管理微服务的具体例子(译)
- 【iOS】苹果IAP(内购)中沙盒账号使用注意事项
- 【数据极客】任务总结_Week2
- 改变Mysql最大连接数
- git流程一览表
- Fragement+RationGroup实现导航的核心
- faster-rcnn学习