HeapByteBuffer和DirectByteBuffer以及回收DirectByteBuffer

简介: 由于HeapByteBuffer和DirectByteBuffer类都是default类型的,所以你无法字节访问到,你只能通过ByteBuffer间接访问到它,因为JVM不想让你访问到它。 分配HeapByteBuffer的方法是: ByteBuffer.

由于HeapByteBuffer和DirectByteBuffer类都是default类型的,所以你无法字节访问到,你只能通过ByteBuffer间接访问到它,因为JVM不想让你访问到它。

分配HeapByteBuffer的方法是:

ByteBuffer.allocate(int capacity);参数大小为字节的数量

分配DirectByteBuffer的方法是:

ByteBuffer.allocateDirect(int capacity);//可以看到分配内存是通过unsafe.allocateMemory()来实现的,这个unsafe默认情况下java代码是没有能力可以调用到的,不过你可以通过反射的手段得到实例进而做操作,当然你需要保证的是程序的稳定性,既然叫unsafe的,就是告诉你这不是安全的,其实并不是不安全,而是交给程序员来操作,它可能会因为程序员的能力而导致不安全,而并非它本身不安全。

 

1、HeapByteBuffer与DirectByteBuffer,在原理上,前者可以看出分配的buffer是在heap区域的,其实真正flush到远程的时候会先拷贝得到直接内存,再做下一步操作(考虑细节还会到OS级别的内核区直接内存),其实发送静态文件最快速的方法是通过OS级别的send_file,只会经过OS一个内核拷贝,而不会来回拷贝;在NIO的框架下,很多框架会采用DirectByteBuffer来操作,这样分配的内存不再是在java heap上,而是在C heap上,经过性能测试,可以得到非常快速的网络交互,在大量的网络交互下,一般速度会比HeapByteBuffer要快速好几倍。

2、DirectByteBuffer这块区域不是在java heap上,那么这块内存的大小是多少呢?默认是一般是64M,可以通过参数:-XX:MaxDirectMemorySize来控制。

3、直接内存好,我们为啥不都用直接内存?请注意,这个直接内存的释放并不是由你控制的,而是由full gc来控制的,直接内存会自己检测情况而调用system.gc(),但是如果参数中使用了DisableExplicitGC(这个参数作用是禁止代码中显示调用GC),那么如何才能释放直接内存呢?

4、那么full gc不触发,我想自己释放这部分内存有方法吗?可以的,我们看到它的源码中DirectByteBuffer发现有一个:Cleaner,是用来搞资源回收的。DirectByteBuffer类是Default类型的,因此这个类无法直接引用到,是通过反射去找到cleaner的实例,进而调用内部的clean方法,那样做麻烦了,其实并不需要那么麻烦,因为DirectByteBuffer implements了DirectBuffer,而DirectBuffer本身是public的,所以通过接口去调用内部的Clear对象来做clean方法。

下面来做测试来证明这个程序是有效地回收的:

import java.nio.ByteBuffer;
import sun.nio.ch.DirectBuffer;
 
public class DirectByteBufferCleaner {
 
        public static void clean(final ByteBuffer byteBuffer) {
              if (byteBuffer.isDirect()) {
                 ((DirectBuffer)byteBuffer).cleaner().clean();
              }
        }
}

public static void sleep(long i) {
    try {
          Thread.sleep(i);
     }catch(Exception e) {
          /*skip*/
     }
}
public static void main(String []args) throws Exception {
       ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024 * 100);
       System.out.println("start");
       sleep(10000);
       clean(buffer);
       System.out.println("end");
       sleep(10000);
}

这里分配了100M内存,为了将结果看清楚,在执行前,执行后分别看看延迟10s,请提前将OS的资源管理器打开,看看当前使用的内存是多少,如果你是linux当然是看看free或者用top等命令来看;本地程序我是用windows完成,在运行前机器的内存如下图所示:

开始运行在输入start后,但是未输出end前,内存直接上升将近100m。

 

在输入end后发现内存立即降低到2.47m,说明回收是有效的。

此时可以观察JVM堆的内存,不会有太多的变化,注意:JVM本身启动后也有一些内存开销,所以不要将那个开销和这个绑定在一起;这里之所以一次性申请100m也是为了看清楚过程。

 

目录
相关文章
|
城市大脑 算法 数据可视化
数字孪生核心技术揭秘(六):传统三维gis与数字孪生的区别
当前对“数字孪生城市”没有一个严格界定的标准,本质上“数字孪生城市”是在传统三维GIS应用的基础上演化而来;随着技术创新和行业需求的发展,两者的差异也越来越大;本文梳理了两者的异同,同时比较了两者的适用场景。
5326 1
数字孪生核心技术揭秘(六):传统三维gis与数字孪生的区别
Cron表达式范例:每隔5秒执行一次:*/5 * * * * ?
Cron表达式范例: 每隔5秒执行一次:*/5 * * * * ? 每隔1分钟执行一次:0 */1 * * * ? 每天23点执行一次:0 0 23 * * ? ...
6911 0
|
8月前
|
人工智能 监控 JavaScript
Crack Coder:在线面试“AI外挂”!编程问题秒出答案,完全绕过屏幕监控,连录屏都抓不到痕迹!
Crack Coder 是一款开源的隐形 AI 辅助工具,专为技术面试设计,支持多种编程语言,提供实时编程问题解决方案,帮助面试者高效解决问题。
393 14
|
10月前
|
小程序 API 开发工具
Mpay: 真的找到啦,后台一直有同学想要解决个人免签收款的问题,这款专注于个人免签收款,轻量级且高效的支付解决方案
嗨,大家好,我是小华同学。mpay是一个基于微信支付官方SDK封装的库,简化了微信支付集成过程,支持公众号、扫码、小程序支付等场景。它提供简洁API、全面错误处理和灵活配置选项,适用于电商网站、线下实体店和移动应用,提升支付体验和运营效率。
462 58
|
前端开发 UED 容器
使用 Flex 布局实现垂直居中效果
【10月更文挑战第7天】
1301 57
|
存储 安全 搜索推荐
想要解析邮件?IMAP协议轻松助你,不再烦恼!
电子邮件仍是关键的通讯工具,利用编程语言自动化处理能显著提高效率。本文介绍使用Go语言从IMAP服务器读取、解析邮件及处理相关信息。首先概述POP3/IMAP/SMTP协议的作用,强调IMAP协议的优势及其在邮件客户端与服务器间双向同步的特点。接着,指导如何获取授权码以连接第三方服务。通过实战演示,展示使用`go-imap`库连接服务器、读取邮件详情(如主题、收件人等)、标记邮件为已读的过程。最后,对比`Store`与`UidStore`方法的区别,指出使用`UidStore`更安全可靠。本文提供了一段详细的Go语言示例代码,帮助读者快速上手。
366 4
|
Ubuntu Linux 文件存储
一台UPS实现NAS、PC和服务器的自动关机
一台UPS实现NAS、PC和服务器的自动关机
|
编解码 jenkins 测试技术
Jenkins 利用HTML Publisher plugin实现HTML文档报告展示
Jenkins 利用HTML Publisher plugin实现HTML文档报告展示
533 0
|
传感器 编解码 缓存
功耗优化 · 入门篇 · 浅析Android耗电量优化(1)
功耗优化 · 入门篇 · 浅析Android耗电量优化
1161 0
功耗优化 · 入门篇 · 浅析Android耗电量优化(1)
|
NoSQL Nacos Redis
Nacos 配置中心实战(二)
Nacos 配置中心实战
1133 0