java中的缓冲类HeapByteBuffer和DirectByteBuffer的区别

使用之前写的文章里的例子

https://blog.csdn.net/zlpzlpzyd/article/details/135292683

HeapByteBuffer

import java.io.File;
import java.io.FileInputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;public class TestHeapByteBuffer implements Serializable {public static void main(String[] args) {long start = System.currentTimeMillis();File file = new File(Control.PATH);ByteBuffer byteBuffer = ByteBuffer.allocate(Control.SIZE);try (FileChannel fileChannel = new FileInputStream(file).getChannel()) {while (fileChannel.read(byteBuffer) > 0) {byteBuffer.clear();}} catch (Throwable e) {e.printStackTrace();}long duration = System.currentTimeMillis() - start;System.out.println(duration);}
}

HeapByteBuffer 在堆上创建的缓冲区,通过 FileChannel 的 read() 读取缓冲区时,会先通过 IOUtil.read() 将 ByteBuffer 获取一个临时 DirectByteBuffer 添加到原来的 ByteBuffer 中。

间接调用 Util 的 getTemporaryDirectBuffer() 获取临时的 DirectByteBuffer,使用完毕后销毁。

可见,HeapByteBuffer 使用的缓冲区不是单纯在堆上处理,还需要借助于 DirectByteBuffer 来处理。

这样就面临一个问题,每次调用 read() 都会造成一个开销问题。

上面只是拿了 read() 来讲解,write() 类似。

DirectByteBuffer

import java.io.File;
import java.io.FileInputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;public class TestDirectByteBuffer implements Serializable {public static void main(String[] args) {long start = System.currentTimeMillis();File file = new File(Control.PATH);ByteBuffer byteBuffer = ByteBuffer.allocateDirect(Control.SIZE);try (FileChannel fileChannel = new FileInputStream(file).getChannel()) {while (fileChannel.read(byteBuffer) > 0) {byteBuffer.clear();}} catch (Throwable e) {e.printStackTrace();}long duration = System.currentTimeMillis() - start;System.out.println(duration);}
}

直接在堆外分配的内存缓冲区,在构造器中有三个操作,如下图

向 Bits 中的变量设置默认值

获取 DirectByteBuffer 的最大直接内存

在 VM 类中可以看到,默认最大值是 64MB,可以通过参数 -XX:MaxDirectMemorySize 进行修改,具体修改参数修改可以参见如下的官方文档

https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

接下来是给 Bits 中的变量赋值

因为参数 size 和 cap 是创建 ByteBuffer 时指定的,totalCapacity 默认值为 0,加上 maxMemory 的值为 64 MB,所以比较式右边的值为 64 MB,cap <= 右边的数据,所以进入循环处理,第一次就停止循环到被调用方停止当前执行方法。

通过 Unsafe 进行分配内存

调用 Unsafe 的 allocateMemory() 先向内存中分配一个新块

调用 Unsafe 的 setMemory() 向分配的内存块中设置对应的字节

创建内存清理者

其中创建的 Deallocator 是一个内部类,创建的对象作为一个后台线程处理。Cleaner 是一个 PhantomReference 对象,即对应的值无法获取。

线程执行的时候会触发 Unsafe 的 freeMemory() 和 Bits.unreserveMemory() 触发堆外的内存清理操作,但是触发时间无法控制。

总结

通过分析可以得出如下

HeapByteBuffer 使用简单,每次执行数据读取写入间接创建 DirectByteBuffer,效率低。

DirectByteBuffer 使用相对麻烦,但是效率高,需要考虑到通过 ByteBuffer 分配的缓冲区与 jvm 参数 -XX:MaxDirectMemorySize 是否合理的问题,不然的在运行过程中会出现内存溢出问题。内部是通过 PhantomReference(Cleaner 的父类)来处理创建的缓冲区,最终通过 Reference 的 clean() 来间接执行堆外内存回收。

为什么使用 DirectByteBuffer

摘自网络上的解答

https://cheng-dp.github.io/2018/12/11/direct-memory-and-direct-byte-buffer/

减少复制操作,加快传输速度

HotSpot虚拟机中,GC除了CMS算法之外,都需要移动对象。

在NIO实现中(如: FileChannel.read(ByteBuffer dst), FileChannel.write(ByteByffer src)), 底层要求连续的内存,且使用期间不得变动, 如果提供的Buffer是HeapByteBuffer,为了保证在数据传输时,被传输的byte数组背后的对象不会被GC回收或者移动,JVM会首先将堆中的byte数组拷贝至直接内存,再由直接内存进行传输。

那么,相比于HeapByteBuffer在堆上分配空间,直接只用DirectByteBuffer在直接内存分配就节省了一次拷贝,加快了数据传输的速度。

减少GC压力

虽然GC仍然管理DirectByteBuffer,但基于DirectByteBuffer分配的空间不属于GC管理,如果IO数量较大,可以明显降低GC压力。

http://lovestblog.cn/blog/2015/05/12/direct-buffer/

DirectByteBuffer在创建的时候会通过Unsafe的native方法来直接使用malloc分配一块内存,这块内存是heap之外的,那么自然也不会对gc造成什么影响(System.gc除外),因为gc耗时的操作主要是操作heap之内的对象,对这块内存的操作也是直接通过Unsafe的native方法来操作的,相当于DirectByteBuffer仅仅是一个壳,还有我们通信过程中如果数据是在Heap里的,最终也还是会copy一份到堆外,然后再进行发送,所以为什么不直接使用堆外内存呢。对于需要频繁操作的内存,并且仅仅是临时存在一会的,都建议使用堆外内存,并且做成缓冲池,不断循环利用这块内存。

DirectByteBuffer 的使用场景

需要频繁操作的小内存,并且仅仅是临时存在一会的,都建议使用堆外内存,并且做成缓冲池,不断循环利用这块内存。

DirectByteBuffer 使用注意事项

摘自网络上的解答

创建和销毁比普通Buffer慢。

虽然DirectByteBuffer的传输速度很快,但是创建和销毁比普通Buffer慢。因此DirectByteBuffer适合只是短时使用需要频繁创建和销毁的场合。

使用直接内存要设置-XX:MaxDirectMemorySize指定最大大小。

直接内存不受GC管理,而基于DirectByteBuffer对象的自动回收过程并不稳定,如DirectByteBuffer对象被MinorGC经过MinorGC进入老年代,但是由于堆内存充足,迟迟没有触发Full GC,DirectByteBuffer将不会被回收,其申请的直接内存也就不会被释放,最终造成直接内存的OutOfMemoryError。

如果我们大面积使用堆外内存并且没有限制,那迟早会导致内存溢出,毕竟程序是跑在一台资源受限的机器上,因为这块内存的回收不是你直接能控制的,当然你可以通过别的一些途径,比如反射,直接使用Unsafe接口等,但是这些务必给你带来了一些烦恼,Java与生俱来的优势被你完全抛弃了—开发不需要关注内存的回收,由gc算法自动去实现。另外上面的gc机制与堆外内存的关系也说了,如果一直触发不了cms gc或者full gc,那么后果可能很严重。

参考链接

https://www.zhihu.com/question/60892134

https://www.cnblogs.com/Chary/p/16718014.html

https://developer.aliyun.com/article/763697

https://juejin.cn/post/6844903744119783431

​​​​​​https://www.infoq.cn/news/2014/12/external-memory-heap-memory/

https://blog.csdn.net/flyzing/article/details/115388720

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/823625.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Linux升级指南:保持系统安全和高效运行

Linux系统的升级是确保系统稳定和安全性的重要步骤。本文将介绍Linux系统升级的基本概念&#xff0c;以及具体的操作步骤和注意事项&#xff0c;以帮助用户顺利升级他们的Linux系统。 Linux操作系统以其稳定性和可定制性而闻名&#xff0c;它经常通过升级来提供新的功能、修复漏…

【论文笔记】Radar Fields: An Extension of Radiance Fields to SAR

原文链接&#xff1a;https://arxiv.org/abs/2312.12961 1. 引言 本文针对合成孔径雷达&#xff08;SAR&#xff09;的3D重建&#xff0c;提出雷达场&#xff0c;基于多个SAR对场景的测量学习体积模型。 3. 辐射场的介绍 NeRF将静态场景表达为连续的体积函数 F \mathcal{F}…

服装店收银系统 助力完善线上线下方案

一个服装店收银系统可以助力完善线上线下方案&#xff0c;提供以下功能和优势&#xff1a; 1. 销售管理&#xff1a;收银系统可以记录每笔销售订单的详细信息&#xff0c;包括商品名称、价格、数量等&#xff0c;方便店主进行销售统计和分析。 2. 库存管理&#xff1a;收银系统…

Android 理解Context

文章目录 Android 理解ContextContext是什么Activity能直接new吗&#xff1f; Context结构和源码一个程序有几个ContextContext的作用Context作用域获取ContextgetApplication()和getApplicationContext()区别Context引起的内存泄露错误的单例模式View持有Activity应用正确使用…

【C语言】数据结构——带头双链表实例探究

&#x1f497;个人主页&#x1f497; ⭐个人专栏——数据结构学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读&#xff1a;1. 双链表结构特征2. 实现双向循环链表2.1 定义结构体2.2 创造节点2.3 双向链表初始化2.4 双向链表打印2…

【数据库系统概论】第7章-数据库设计

文章目录 7.1 数据库设计概述7.2 需求分析7.2.1 需求分析的任务7.2.2 需求分析的难点7.2.2 需求分析的方法7.2.3 数据字典 7.3 概念结构设计7.3.1 概念模型7.3.2 E-R模型7.3.3 概念结构设计 7.4 逻辑结构设计7.4.1 E-R图向关系模型的转换7.4.2 数据模型的优化7.4.3 设计用户子模…

PowerShell Instal 一键部署gitea

gitea 前言 Gitea 是一个轻量级的 DevOps 平台软件。从开发计划到产品成型的整个软件生命周期,他都能够高效而轻松的帮助团队和开发者。包括 Git 托管、代码审查、团队协作、软件包注册和 CI/CD。它与 GitHub、Bitbucket 和 GitLab 等比较类似。 Gitea 最初是从 Gogs 分支而来…

QT上位机开发(倒计时软件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 倒计时软件是生活中经常遇到的一种场景。比如运动跑步&#xff0c;比如学校考试&#xff0c;比如论文答辩等等&#xff0c;只要有时间限制规定的地…

21 UVM printer

uvm_printer 类提供了以不同格式打印 uvm_objects 的灵活性。我们已经讨论了使用 uvm_field_* 宏的 print() 方法&#xff0c;或者如果不使用 utils_begin/ end 宏&#xff0c;则编写 do_print() 方法。 UVM printer提供四种内置printer。 uvm_printeruvm_table_printeruvm_t…

Git:远程仓库的使用

查看当前的远程库 要查看当前配置有哪些远程仓库&#xff0c;可以用git remote 命令&#xff0c;它会列出每个远程库的简短名字。在克隆完某个项目后&#xff0c;至少可以看到一个名为origin 的远程库&#xff0c;Git 默认使用这个名字来标识你所克隆的原始仓库&#xff1a; 也…

DM达梦数据库表占用空间大小

问题描述&#xff1a; 项目涉及用户量大且数据量大&#xff0c;为提高查询性能采用分表方式处理数据&#xff1b;根据业务要求总共4张业务表&#xff0c;每张业务表扩展成100张表&#xff0c;系统中总共400张表。部署至测试环境发现测试环境占用的磁盘空间是开发环境的8倍。 问…

从程序员到项目经理

前言 看到这个话题&#xff0c;博主不禁有感而发。那么就简单讲讲&#xff0c;从程序员到项目经理&#xff0c;需要具备哪些必备能力或基本的素养。 一、必备 1、技术能力 程序员首先必须成为一个名合格的coder&#xff0c;有思想有见解有态度。 无论身处什么开发岗位&…

python2.x编码Unicode字符串

1 python2.x编码Unicode字符串 python2.x默认编码方法为ASCII码。字符串赋值时按系统默认编码自动编码&#xff0c;通过decode()方法解码为Unicode&#xff0c;再通过encode()方法编码为指定码。 1.1 编码解码基础知识 1.1.1 位 位(bit)是计算机存储数据的最小单位&#xf…

数据之光:乡镇企业的发展利器——数据可视化

数据可视化是一项强大的工具&#xff0c;它不仅在大型企业中发挥关键作用&#xff0c;而且在乡镇企业中也能作出显著贡献。那么&#xff0c;数据可视化究竟能为乡镇企业做出什么样的贡献呢&#xff1f; 首先&#xff0c;数据可视化为乡镇企业提供了更清晰的业务洞察。通过将庞大…

超简单实用,推荐的深度学习科研必备网站(轻松找论文,代码项目,写论文综述)

一个非常有用的深度学习必备网站 网址推荐 接触新方向需要了解的内容1.在某一个研究方向下&#xff0c;有哪些算法模型可以用&#xff1f;不同算法之间效果对比如何&#xff1f;2.在某一个研究方向下&#xff0c;到底有哪些论文&#xff0c;模型是可以用的&#xff1f;3.在某一…

Python中如何使用_new_实现单例模式

单例模式是一个经典设计模式&#xff0c;简要的说&#xff0c;一个类的单例模式就是它只能被实例化一次&#xff0c;实例变量在第一次实例化时就已经固定。 在Python中常见的单例模式有None&#xff0c;这就是一个很典型的设计&#xff0c;通常使用 if xxx is None或者if xxx …

ESP32S3+HX8347+3线SPI运行LVGL例程

一、clone lv_port_esp32到本地 git clone https://github.com/lvgl/lv_port_esp32.git 二、增加hx8347.c、hx8347.h components\lvgl_esp32_drivers\lvgl_tft下新增2个文件&#xff1a;hx8347.c、hx8347.h。因为lv_port_esp32中没有hx8347的驱动&#xff0c;需要自己写。这两个…

分库分表之Mycat应用学习二

3 Mycat 概念与配置 官网 http://www.mycat.io/ Mycat 概要介绍 https://github.com/MyCATApache/Mycat-Server 入门指南 https://github.com/MyCATApache/Mycat-doc/tree/master/%E5%85%A5%E9%97%A8%E6%8C%87%E5%8D%973.1 Mycat 介绍与核心概念 3.1.1 基本介绍 历史&#x…

怎么使用FTP

FTP服务器&#xff08;File Transfer Protocol Server&#xff09;是在互联网上提供文件存储和访问服务的计算机&#xff0c;它们依照FTP协议提供服务。FTP是File Transfer Protocol的缩写&#xff0c;即文件传输协议&#xff0c;是一种基于TCP的协议&#xff0c;采用客户/服务…

软件测试/测试开发丨Python 数据类 dataclass 学习笔记

dataclass 介绍 dataclass优势 可读性强操作灵活轻量 应用场景 创建对象完美融合平台开发 ORM 框架 案例 场景&#xff1a;如果创建一只猫&#xff0c;信息包括猫的名字、体重、颜色。同时打印这个对象的时候&#xff0c;希望能打印出一个字符串&#xff08;包含猫的各种信息&…