堆内内存

java的内存分为堆内内存和堆外内存,在了解堆外内存之前,先看看堆内内存是啥,堆内内存是受jvm管控的,也就是说,堆内内存由jvm负责创建和回收;创建和回收都是自动进行的,不需要人为干预;

什么是堆外内存

堆外内存又叫直接内存,是和操作系统内存直接挂钩的,堆外内存不受jvm的管制,所以可以认为堆外内存是jvm以外的内存空间,虽然不受jvm管控,但是堆外内存还是在java进程里面的,而不是由系统内核直接管理;所以它还是在java进程里面的;(终究逃不出java的手掌心);

堆外内存和堆内内存他俩是没有任何关系的;当我们在使用堆内内存的对象时,如果对象内存占用超过了申请的堆内存,就会产生OOM异常(内存溢出);而堆外内存是直接向操作系统申请新的内存空间,理论上只要操作系统的内存足够,堆外内存想申请多少都行!

为什么需要堆外内存

因为堆外内存不受jvm的管控,因此,它有以下几个优点:

1、减少垃圾回收次数

垃圾回收机制不会回收堆外内存,所以使用堆外内存可以减少垃圾回收次数,提升运行效率;因为垃圾回收工作时会暂停工作线程;

2、 加快复制的速度

因为堆内在flush到远程时,会先复制到堆内内存,在复制到堆外内存,然后在发送;操作系统是不可直接访问堆内内存的,而堆外内存省去了堆内到堆外的复制工作;比如netty框架就是用了直接内存才会如此之快;

堆外内存的缺点

  1. 因为不受jvm管控,所以垃圾回收机制不会回收直接内存的空间,需要用户自己释放内存空间
  2. 堆外内存一旦发生泄漏,很难排查,所以,一定要对堆外内存足够了解再去使用堆外内存;
  3. 不适合存储很复杂的对象。一般简单的对象或者扁平化的比较适合;

实验代码

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释放堆外内存

网上有些文章说使用cleanerSystem.gc()都可以释放直接内存,但是经过博主试验后发现只有cleaner才可以释放直接内存;调用System.gc()方法后未起作用;这一点也是需要注意的;

另外,如果在运行过程中直接终止java进程的话也会释放直接内存;所以博主认为虽然是直接向操作系统申请的内存,但是这一块内存并不是由操作系统管理的,而是在java进程里面的;

java堆外内存详解(又名直接内存)和ByteBuffer相关推荐

  1. OOM系列之一:java.lang.OutOfMemoryError: Java堆空间问题详解

    第一篇:java.lang.OutOfMemoryError: Java heap space Java 应用程序只允许使用有限的内存量.此限制是在应用程序启动期间指定的.为了让事情变得更复杂,Jav ...

  2. linux系统分配文件夹内存,详解Linux系统内存知识及调优方案

    内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁.计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大.内存作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器 ...

  3. Java基础学习总结(58)——JAVA堆、栈详解

    关于堆栈的内容网上已经有很多资料了,这是我找的加上自己理解的一篇说明文:

  4. java 堆外内存_详解Java堆外内存

    临近春节,最近有点时间,准备顺着上篇专栏的思路写下去,建议先阅读: juejin.im/post/684490- 武汉那几个吃野味的傻[],请藏好你们的妈 正文开始 在运行Java程序时,java虚拟 ...

  5. JVM(Java虚拟机)详解(JVM 内存模型、堆、GC、直接内存、性能调优)

    JVM(Java虚拟机) JVM 内存模型 结构图 jdk1.8 结构图(极简) jdk1.8 结构图(简单) JVM(Java虚拟机): 是一个抽象的计算模型. 如同一台真实的机器,它有自己的指令集 ...

  6. java堆内存_java堆内存详解

    http://www.importnew.com/14630.html java堆的特点 <深入理解java虚拟机>是什么描述java堆的 Java堆(Java Heap)是java虚拟机 ...

  7. java堆外内存6_Java 堆外内存的使用

    更多 Java 虚拟机方面的文章,请参见文集<Java 虚拟机> 为什么需要使用堆外内存 将长期存活的对象(如 Local Cache )移入堆外内存( off-heap,又名直接内存 d ...

  8. Cassandra Java堆外内存排查经历全记录

    背景 最近准备上线cassandra这个产品,同事在做一些小规格ECS(8G)的压测.压测时候比较容易触发OOM Killer,把cassandra进程干掉.问题是8G这个规格我配置的heap(Xmx ...

  9. 记一次Cassandra Java堆外内存排查经历

    背景 最近准备上线cassandra这个产品,同事在做一些小规格ECS(8G)的压测.压测时候比较容易触发OOM Killer,把cassandra进程干掉.问题是8G这个规格我配置的heap(Xmx ...

  10. java 堆外内存 查看_超干货!Cassandra Java堆外内存排查经历全记录

    背景 最近准备上线cassandra这个产品,同事在做一些小规格ECS(8G)的压测.压测时候比较容易触发OOM Killer,把cassandra进程干掉.问题是8G这个规格我配置的heap(Xmx ...

最新文章

  1. 07 分支管理 —— Feature分支
  2. C++中的volatile关键字
  3. HDU 1856 More is better【并查集】
  4. saltui试用遇到的问题
  5. 2016年科技阅读列表
  6. 那些年的那些事CISC和RISC发展中的纠缠
  7. 用FPGA搭建一个STM32内核?
  8. JAVA 框架-Spring-AOP面向切面
  9. leetcode 538. 把二叉搜索树转换为累加树 思考分析
  10. python在线编辑器手机-QPython,一个在手机上运行Python的神器
  11. Gstreamer之gst-plugin-bad交叉编译集成x265(二十二)
  12. git add 所有修改文件_工作中Git的使用实践
  13. 华为鸿蒙2048小游戏,从零开始使用华为DevEco Studio编写2048小游戏
  14. SSM员工工资管理系统(Java毕设项目)
  15. 截图工具-picpick绿色破解版免安装
  16. 芝诺数解|「十六」绿水青山就是金山银山——重庆环保
  17. 电脑的CPU主频1.8GHZ够不够用
  18. 狠狠报复了出轨的丈夫和他的情人——转载
  19. C#游戏跨服架构进化之路
  20. 如何爬取微博全部粉丝python_python 登录新浪微博爬取粉丝信息

热门文章

  1. 数据结构:线性表(List)【详解】
  2. ## 线上实验五:2个2位二进制乘法器
  3. OpenTelemetry系列 (三)| 神秘的采集器 - Opentelemetry Collector
  4. ubuntu 删除Indicator Applet中的邮件图标
  5. 产品之我见(2)-求职APP
  6. 微信小程序-购买系列
  7. mysql innodb repair,草泥马之家
  8. CrapApi接口管理系统菜单设置
  9. Android如何实时监控CPU频率
  10. python win32con键位表_关于pywin32的完整键位码表