NIO的Buffer提供了一个可以不经过JVM内存直接访问系统物理内存的类——DirectBuffer。 DirectBuffer类继承自ByteBuffer,但和普通的ByteBuffer不同,普通的ByteBuffer仍在JVM堆上分配内存,其最大内存受到最大堆内存的限制;而DirectBuffer直接分配在物理内存中,并不占用堆空间,其可申请的最大内存受操作系统限制。
直接内存的读写操作比普通Buffer快,但它的创建、销毁比普通Buffer慢(猜测原因是DirectBuffer需向OS申请内存涉及到用户态内核态切换,而后者则直接从堆内存划内存即可)。
因此直接内存使用于需要大内存空间且频繁访问的场合,不适用于频繁申请释放内存的场合。
(Note:DirectBuffer并没有真正向OS申请分配内存,其最终还是通过调用Unsafe的allocateMemory()来进行内存分配。不过JVM对Direct Memory可申请的大小也有限制,可用-XX:MaxDirectMemorySize=1M设置,这部分内存不受JVM垃圾回收管理。)
使用对外内存的原因:
- 对垃圾回收停顿的改善。由于堆外内存是直接受操作系统管理而不是JVM,所以当我们使用堆外内存时,即可保持较小的堆内内存规模。从而在GC时减少回收停顿对于应用的影响。
- 提升程序I/O操作的性能。通常在I/O通信过程中,会存在堆内内存到堆外内存的数据拷贝操作,对于需要频繁进行内存间数据拷贝且生命周期较短的暂存数据,都建议存储到堆外内存。
以下是一些测试:
代码:
class DirectMemory { // 分配堆内存
public static void bufferAccess() {
long startTime = System.currentTimeMillis();
ByteBuffer b = ByteBuffer.allocate(500);
for (int i = 0; i < 1000000; i++) {
for (int j = 0; j < 99; j++)
b.putInt(j);
b.flip();
for (int j = 0; j < 99; j++)
b.getInt();
b.clear();
}
long endTime = System.currentTimeMillis();
System.out.println("access_nondirect:" + (endTime - startTime));
} // 直接分配内存
public static void directAccess() {
long startTime = System.currentTimeMillis();
ByteBuffer b = ByteBuffer.allocateDirect(500);
for (int i = 0; i < 1000000; i++) {
for (int j = 0; j < 99; j++)
b.putInt(j);
b.flip();
for (int j = 0; j < 99; j++)
b.getInt();
b.clear();
}
long endTime = System.currentTimeMillis();
System.out.println("access_direct:" + (endTime - startTime));
} public static void bufferAllocate() {
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
ByteBuffer.allocate(1000);
}
long endTime = System.currentTimeMillis();
System.out.println("allocate_nondirect:" + (endTime - startTime));
} public static void directAllocate() {
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
ByteBuffer.allocateDirect(1000);
}
long endTime = System.currentTimeMillis();
System.out.println("allocate_direct:" + (endTime - startTime));
} public static void main(String args[]) {
System.out.println("访问性能测试:");
bufferAccess();
directAccess(); System.out.println(); System.out.println("分配性能测试:");
bufferAllocate();
directAllocate();
}
}
结果:
访问性能测试:
access_nondirect:157
access_direct:134 分配性能测试:
allocate_nondirect:231
allocate_direct:613
可见与在JVM堆分配内存(allocate)相比,直接内存分配(allocateDirect)的访问性能更好,但分配较慢。(一般如此,当然数据量小的话差别不是那么明显)
Java直接内存与堆内存的更多相关文章
-
牛客网Java刷题知识点之内存的划分(寄存器、本地方法区、方法区、栈内存和堆内存)
不多说,直接上干货! 其中 1)程序计数器:用于指示当前线程所执行的字节码执行到了第几行,可以理解为当前线程的行号指示器.每个计数器志勇赖记录一个线程的行号,所以它是线程私有的. ...
-
JVM存储位置分配——java中局部变量、实例变量和静态变量在方法区、栈内存、堆内存中的分配
Java中的变量根据不同的标准可以分为两类,以其引用的数据类型的不同来划分可分为“原始数据类型变量和引用数据类型变量”,以其作用范围的不同来区分可分为“局部变量,实例变量和静态变量”. 根据“Java ...
-
Java中局部变量、实例变量和静态变量在方法区、栈内存、堆内存中的分配
转自:https://blog.csdn.net/leunging/article/details/80599282 感谢CSDN博主「leunging」的总结分享 ———————————————— ...
-
(转)java内存分配分析/栈内存、堆内存
转自(http://blog.csdn.net/qh_java/article/details/9084091) java内存分配分析/栈内存.堆内存 java内存分配分析 本文将由浅入深详细介绍Ja ...
-
java中栈内存与堆内存(JVM内存模型)
java中栈内存与堆内存(JVM内存模型) Java中堆内存和栈内存详解1 和 Java中堆内存和栈内存详解2 都粗略讲解了栈内存和堆内存的区别,以及代码中哪些变量存储在堆中.哪些存储在栈中.内存中的 ...
-
Docker环境下Java应用的最大内存和堆内存的设置
Docker环境下Java应用的最大内存和堆内存的设置 1. 设置应用允许使用的最大内存 通过docker run(创建一个新的容器并运行)命令中设置-m来进行设置.案例如下所示. docker r ...
-
目录_Java内存分配(直接内存、堆内存、Unsafel类、内存映射文件)
1.Java直接内存与堆内存-MarchOn 2.Java内存映射文件-MarchOn 3.Java Unsafe的使用-MarchOn 简单总结: 1.内存映射文件 读文件时候一般要两次复制:从磁盘 ...
-
(转)JVM内存管理-----堆内存
来源:http://blog.csdn.net/yu422560654/article/details/7952613 Heap堆内存理解 一个JVM实例只有一个堆内存,堆内存的大小是可以调节的.类加 ...
-
JS栈内存与堆内存
㈠JavaScript变量 ⒈分类 ⑴JavaScript中的变量分为基本类型和引用类型. ⑵基本类型就是保存在栈内存中的简单数据段. ⑶引用类型指的是那些保存在堆内存中的对象. ⒉基本类型 基本类 ...
-
JavaScript变量——栈内存or堆内存
原文 http://blog.csdn.net/xdd19910505/article/details/41900693 堆和栈这两个字我们已经接触多很多次,那么具体是什么存在栈中什么存在堆中呢?就 ...
随机推荐
-
Android 窗体设置
requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG ...
-
关于HTML面试题汇总之visibility
一.页面可见性(visibility) 主要提供两个属性,一个事件(都在document对象上):1. 属性: 1.1. hidden:获取或设置当前页面的可见性,boolean值: 1.2 ...
-
JavaScript中的prototype使用说明
参考 http://abruzzi.iteye.com/blog/1026125 http://www.jb51.net/article/23052.htm
-
APP运营推广那点事【干货】
你的手机里面有多少应用?什么样的手机应用吸引你?下载之后经常用还是让他shi在那里?又或者刚点进去就卸载? 一款成功的应用,开发APP只是第一步,比前者更重要的是“养”APP,APP就像是一个需要不断 ...
-
在UWSGI和NGINX配合的情况下,配置个别目录上传及超时
笨办法就是多加一个LOCATION. 然后,自定义以下类似参数 client_max_body_size uwsgi_connect_timeout uwsgi_read_timeout server ...
-
网易云课堂_C++程序设计入门(上)_第2单元:丹青画松石– EGE图形库
第2节:一个简单的EGE程序 #ifndef _GRAPHICS_H_ #define _GRAPHICS_H_ #ifndef __cplusplus #error You must use C++ ...
-
hdu_5889_Barricade(最小割+最短路)
题目链接:hdu_5889_Barricade 题意: 有n个点,m条边,每个边的长度都为1,每个边有一个消耗w,如果要阻断这条路,那么就会消耗w,现在让你阻断点1到点n的所有最短路,问你最小的消耗是 ...
-
刨根究底字符编码之十一——UTF-8编码方式与字节序标记
UTF-8编码方式与字节序标记 一.UTF-8编码方式 1. 接下来将分别介绍Unicode字符集的三种编码方式:UTF-8.UTF-16.UTF-32.这里先介绍应用最为广泛的UTF-8. 为满足基 ...
-
PYTHON实现算术表达式构造二叉树
LEETCOCE 224. Basic Calculator Implement a basic calculator to evaluate a simple expression string. ...
-
TweenMax 动画库,知识点
官方地址:https://greensock.com/tweenmax github 地址:https://github.com/greensock/GreenSock-JS 比较好的介绍文章: ht ...