java堆外内存详解(又名直接内存)和ByteBuffer
堆内内存
java的内存分为堆内内存和堆外内存,在了解堆外内存之前,先看看堆内内存是啥,堆内内存是受jvm管控的,也就是说,堆内内存由jvm负责创建和回收;创建和回收都是自动进行的,不需要人为干预;
什么是堆外内存
堆外内存又叫直接内存,是和操作系统内存直接挂钩的,堆外内存不受jvm的管制,所以可以认为堆外内存是jvm以外的内存空间,虽然不受jvm管控,但是堆外内存还是在java进程里面的,而不是由系统内核直接管理;所以它还是在java进程里面的;(终究逃不出java的手掌心);
堆外内存和堆内内存他俩是没有任何关系的;当我们在使用堆内内存的对象时,如果对象内存占用超过了申请的堆内存,就会产生OOM异常(内存溢出);而堆外内存是直接向操作系统申请新的内存空间,理论上只要操作系统的内存足够,堆外内存想申请多少都行!
为什么需要堆外内存
因为堆外内存不受jvm的管控,因此,它有以下几个优点:
1、减少垃圾回收次数
垃圾回收机制不会回收堆外内存,所以使用堆外内存可以减少垃圾回收次数,提升运行效率;因为垃圾回收工作时会暂停工作线程;
2、 加快复制的速度
因为堆内在flush到远程时,会先复制到堆内内存,在复制到堆外内存,然后在发送;操作系统是不可直接访问堆内内存的,而堆外内存省去了堆内到堆外的复制工作;比如netty框架就是用了直接内存才会如此之快;
堆外内存的缺点
- 因为不受jvm管控,所以垃圾回收机制不会回收直接内存的空间,需要用户自己释放内存空间
- 堆外内存一旦发生泄漏,很难排查,所以,一定要对堆外内存足够了解再去使用堆外内存;
- 不适合存储很复杂的对象。一般简单的对象或者扁平化的比较适合;
实验代码
1、 Unsafe类
接下来我们使用Unsafe类来申请1G的直接内存,并且在末尾释放内存,在这期间我们观测堆内内存和操作系统的使用情况;
@Testpublic void test1() throws Exception {// 查看内存使用情况showHeapSpace();// 创建unsafe实例Constructor<Unsafe> declaredConstructor = Unsafe.class.getDeclaredConstructor();declaredConstructor.setAccessible(true);Unsafe unsafe = declaredConstructor.newInstance();// 1G内存空间int size = 1024 * 1024* 1024;// 创建堆外内存大小为1G,此时只是配置堆外内存的大小,并未申请内存long address = unsafe.allocateMemory(size);// 初始化堆外内存,传入基础地址address、长度为size,也就是说从address地址开始,一直到 address + size的地址都设为0;unsafe.setMemory( address,size,(byte)0);// 睡5秒TimeUnit.SECONDS.sleep(5);// 传入地址位置,设置byte值unsafe.putByte(address+1, (byte) 66);unsafe.putByte(address+2, (byte) 77);unsafe.putByte(address+3, (byte) 88);// 查看堆内存使用情况showHeapSpace();// 获取值System.out.println(unsafe.getByte(address+1));System.out.println(unsafe.getByte(address+2));System.out.println(unsafe.getByte(address+3));// 释放堆外内存unsafe.freeMemory(address);// 查看堆内存使用情况showHeapSpace();}/*** 展示堆空间大小*/public void showHeapSpace(){long coreSize = Runtime.getRuntime().totalMemory() / 1024 / 1024;long maxSize = Runtime.getRuntime().maxMemory() / 1024 / 1024;long freeSize = Runtime.getRuntime().freeMemory() / 1024 / 1024;System.out.println("当前堆内已申请内存:" + coreSize + "M," +"最大内存:"+maxSize+ "M,已申请空闲内存:" + freeSize+ "M");}
运行后控制台打印结果如下,可以看到堆内存没什么变化,所以可以得出结论直接内存并未使用到堆内内存;
当前堆内已申请内存:245M,最大内存:3616M,已申请空闲内存:235M
当前堆内已申请内存:245M,最大内存:3616M,已申请空闲内存:233M
66
77
88
当前堆内已申请内存:245M,最大内存:3616M,已申请空闲内存:233M
既然在java层面看不到直接内存的使用情况,那我们就只能看任务管理器了,在win10的任务栏右键打开任务管理器,然后在运行一遍上面的代码;任务管理器的绘图图表如下
根据图片可以看到,图中凸起的部分就是我们刚刚申请到的1G直接内存;因为让绘图的时间长一些,所以延时了5秒,执行到unsafe.setMemory( address,size,(byte)0);
就会往操作系统申请内存,执行到unsafe.freeMemory(address);
时会立马释放内存;
2、ByteBUffer
相信学习过IO的童鞋们都知道这个类,ByteBUffer 有2种模式,可以使用堆外也可以使用堆内内存,以为本文章的主题是堆外内存,所以在这里我们只测试堆外内存;
@Testpublic void test() throws Exception {showHeapSpace();// 使用堆外内存创建1G空间ByteBuffer buffer1 = ByteBuffer.allocateDirect(1024*1024*1024);showHeapSpace();buffer1.put(new byte[]{123});// 睡5秒TimeUnit.SECONDS.sleep(5);showHeapSpace();// 释放堆外内存DirectBuffer directBuffer = (DirectBuffer) buffer1;directBuffer.cleaner().clean(); // gc方法并不能释放堆外内存
// System.gc();}
运行后打印结果如下,也是是用了直接内存
当前堆内已申请内存:245M,最大内存:3616M,已申请空闲内存:235M
当前堆内已申请内存:245M,最大内存:3616M,已申请空闲内存:235M
当前堆内已申请内存:245M,最大内存:3616M,已申请空闲内存:235M
在来看看任务管理器,也有一个凸起的部分,代表这段代码也使用了直接内存;
ByteBuffer释放堆外内存
网上有些文章说使用cleaner
和System.gc()
都可以释放直接内存,但是经过博主试验后发现只有cleaner
才可以释放直接内存;调用System.gc()
方法后未起作用;这一点也是需要注意的;
另外,如果在运行过程中直接终止java进程的话也会释放直接内存;所以博主认为虽然是直接向操作系统申请的内存,但是这一块内存并不是由操作系统管理的,而是在java进程里面的;
完
java堆外内存详解(又名直接内存)和ByteBuffer相关推荐
- OOM系列之一:java.lang.OutOfMemoryError: Java堆空间问题详解
第一篇:java.lang.OutOfMemoryError: Java heap space Java 应用程序只允许使用有限的内存量.此限制是在应用程序启动期间指定的.为了让事情变得更复杂,Jav ...
- linux系统分配文件夹内存,详解Linux系统内存知识及调优方案
内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁.计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大.内存作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器 ...
- Java基础学习总结(58)——JAVA堆、栈详解
关于堆栈的内容网上已经有很多资料了,这是我找的加上自己理解的一篇说明文:
- java 堆外内存_详解Java堆外内存
临近春节,最近有点时间,准备顺着上篇专栏的思路写下去,建议先阅读: juejin.im/post/684490- 武汉那几个吃野味的傻[],请藏好你们的妈 正文开始 在运行Java程序时,java虚拟 ...
- JVM(Java虚拟机)详解(JVM 内存模型、堆、GC、直接内存、性能调优)
JVM(Java虚拟机) JVM 内存模型 结构图 jdk1.8 结构图(极简) jdk1.8 结构图(简单) JVM(Java虚拟机): 是一个抽象的计算模型. 如同一台真实的机器,它有自己的指令集 ...
- java堆内存_java堆内存详解
http://www.importnew.com/14630.html java堆的特点 <深入理解java虚拟机>是什么描述java堆的 Java堆(Java Heap)是java虚拟机 ...
- java堆外内存6_Java 堆外内存的使用
更多 Java 虚拟机方面的文章,请参见文集<Java 虚拟机> 为什么需要使用堆外内存 将长期存活的对象(如 Local Cache )移入堆外内存( off-heap,又名直接内存 d ...
- Cassandra Java堆外内存排查经历全记录
背景 最近准备上线cassandra这个产品,同事在做一些小规格ECS(8G)的压测.压测时候比较容易触发OOM Killer,把cassandra进程干掉.问题是8G这个规格我配置的heap(Xmx ...
- 记一次Cassandra Java堆外内存排查经历
背景 最近准备上线cassandra这个产品,同事在做一些小规格ECS(8G)的压测.压测时候比较容易触发OOM Killer,把cassandra进程干掉.问题是8G这个规格我配置的heap(Xmx ...
- java 堆外内存 查看_超干货!Cassandra Java堆外内存排查经历全记录
背景 最近准备上线cassandra这个产品,同事在做一些小规格ECS(8G)的压测.压测时候比较容易触发OOM Killer,把cassandra进程干掉.问题是8G这个规格我配置的heap(Xmx ...
最新文章
- 07 分支管理 —— Feature分支
- C++中的volatile关键字
- HDU 1856 More is better【并查集】
- saltui试用遇到的问题
- 2016年科技阅读列表
- 那些年的那些事CISC和RISC发展中的纠缠
- 用FPGA搭建一个STM32内核?
- JAVA 框架-Spring-AOP面向切面
- leetcode 538. 把二叉搜索树转换为累加树 思考分析
- python在线编辑器手机-QPython,一个在手机上运行Python的神器
- Gstreamer之gst-plugin-bad交叉编译集成x265(二十二)
- git add 所有修改文件_工作中Git的使用实践
- 华为鸿蒙2048小游戏,从零开始使用华为DevEco Studio编写2048小游戏
- SSM员工工资管理系统(Java毕设项目)
- 截图工具-picpick绿色破解版免安装
- 芝诺数解|「十六」绿水青山就是金山银山——重庆环保
- 电脑的CPU主频1.8GHZ够不够用
- 狠狠报复了出轨的丈夫和他的情人——转载
- C#游戏跨服架构进化之路
- 如何爬取微博全部粉丝python_python 登录新浪微博爬取粉丝信息