java heap buffer direct buffer_java NIO - DirectBuffer 和 HeapBuffer

问题 :

DirectBuffer 属于堆外存,那应该还是属于用户内存,而不是内核内存?

FileChannel 的read(ByteBuffer dst)函数,write(ByteBuffer src)函数中,如果传入的参数是HeapBuffer类型,则会临时申请一块DirectBuffer,进行数据拷贝,而不是直接进行数据传输,这是出于什么原因?

DirectBuffer

Java | native

|

DirectByteBuffer | malloc'd

[ address ] -+-> [ data ]

|

DirectByteBuffer 自身是一个Java对象,在Java堆中;而这个对象中有个long类型字段address,记录着一块调用 malloc() 申请到的native memory。DirectByteBuffer 自身是(Java)堆内的,它背后真正承载数据的buffer是在(Java)堆外——native memory中的。这是 malloc() 分配出来的内存,是用户态的。(来自参考文章R大的回答)

DirectBuffer 和 HeapBuffer

两个都是Buffer ,不同的是前者使用的是堆外内存,后者时候的是 JVM 堆内内存。在使用 FileChannel 读写的时候内部实现就有点不同了。以下是FileChannel使用代码

public static void main(String[] args) throws Exception{

RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");

FileChannel channel = aFile.getChannel();

String newData = "New String to write to file..." + System.currentTimeMillis();

// HeapByteBuffer

ByteBuffer buf = ByteBuffer.allocate(48);

// DirectByteBuffer

ByteBuffer dirctBuf = ByteBuffer.allocateDirect(48);

buf.clear();

buf.put(newData.getBytes());

buf.flip();

while(buf.hasRemaining()) {

channel.write(buf);

}

}

//读取地址

FileInputStream fis = new FileInputStream("C:\\CloudMusic\\Circadian Eyes - Ferris Wheel.mp3");

//写出地址

FileOutputStream fos = new FileOutputStream("D:\\etc\\cas\\logs\\cas_audit.log");

FileChannel fc = fis.getChannel();

MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());

//回刷回磁盘

mbb.flip();

fos.flush();

fc.close();

fis.close();

如果上面的代码channel.write传入的参数是HeapBuffer类型,则会临时申请一块DirectBuffer,将HeapBuffer中的数据进行数据拷贝到堆外内存,然后剩下就是对DirectBuffer进行IO操作,为什么直接使用HeapBuffer拷贝数据到内核中,然后进行IO操作呢?这是因为如果要把一个Java里的 byte[] 对象的引用传给native代码,让native代码直接访问数组的内容的话,就必须要保证native代码在访问的时候这个 byte[] 对象不能被移动,也就是要被“pin”(钉)住。而虚拟机的GC 算法会移动对象,导致地址会变化,那么后续就会产生错误。详细的见参考资料R大的回答。  OpenJDK的 sun.nio.ch.IOUtil.write(FileDescriptor fd, ByteBuffer src, long position, NativeDispatcher nd) 的实现。

static int write(FileDescriptor fd, ByteBuffer src, long position,

NativeDispatcher nd)

throws IOException

{

if (src instanceof DirectBuffer)

return writeFromNativeBuffer(fd, src, position, nd);

// Substitute a native buffer

int pos = src.position();

int lim = src.limit();

assert (pos <= lim);

int rem = (pos <= lim ? lim - pos : 0);

ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);

try {

bb.put(src);

bb.flip();

// Do not update src until we see how many bytes were written

src.position(pos);

int n = writeFromNativeBuffer(fd, bb, position, nd);

if (n > 0) {

// now update src

src.position(pos + n);

}

return n;

} finally {

Util.offerFirstTemporaryDirectBuffer(bb);

}

}

MappedByteBuffer

MappedByteBuffer 是 DirectBuffer 的父类,它的读写性能比HeapByteBuffer要高(不然FileChannel 内部实现中也不会用DirectByteBuffer进行操作)。MappedByteBuffer 内部原理主要和操作系统的虚拟存储有关,更加直接的联系就是页表相关的知识,先阅读以下这篇文章。

补充

关于 Heap memory 和 Native memory的解释,来自stackoverflow

Heap memory: memory within the JVM process that is managed by the JVM to represent Java objects

Native memory/Off-heap: is memory allocated within the processes address space that is not within the heap.

Direct memory: is similar to native, but also implies that an underlying buffer within the hardware is being shared. For example buffer within the network adapter or graphics display. The goal here is to reduce the number of times the same bytes is being copied about in memory.

Finally, depending upon the OS then extra native allocations (assigning of the memory address space) can be carried out via Unsafe alloc and/or by memory mapping a file. Memory mapping a file is especially interesting as it can easily allocate more memory than the machine currently has as physical ram. Also note, that the total address space limit is restricted by the size of a pointer being used, a 32bit pointer cannot go outside of 4GB. Period.

参考资料

https://www.zhihu.com/question/57374068 (推荐一看)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

yii2 提供接口给java_yii2写api接口步骤

yii2写api接口步骤Yii2如何实现RESTful风格的API(推荐&#xff1a;《YII教程》 )1、建立单独的应用程序为了增加程序的可维护性&#xff0c;易操作性&#xff0c;我们选择新建一套应用程序&#xff0c;这也是为了和前台应用、后台应用区分开操作。在WEB前端(frontend)和后端(ba…

java caller_js中的caller和callee属性

caller返回一个对函数的引用&#xff0c;该函数调用了当前函数。functionName.callerfunctionName 对象是所执行函数的名称。如果一个函数f是在全局作用域内被调用的,则f.caller为null,相反,如果一个函数是在另外一个函数作用域内被调用的,则f.caller指向调用它的那个函数.该属…

mysql 备份 php_PHP备份/还原MySQL数据库的代码

一、备份数据库并下载到本地// 设置SQL文件保存文件名$filenamedate("Y-m-d_H-i-s")."-".$cfg_dbname.".sql";// 所保存的文件名header("Content-disposition:filename".$filename);header("Content-type:application/octetstrea…

java代码修改触发编译_gcc -O0仍然优化了“未使用”的代码 . 是否有一个编译标志来改变它?...

当我在this question中提出时&#xff0c;gcc正在移除(是的&#xff0c;使用 -O0 )一行代码 _mm_div_ss(s1, s2); &#xff0c;大概是因为结果未保存 . 但是&#xff0c;这应该触发浮点异常并引发SIGFPE&#xff0c;如果删除调用则不会发生这种情况 .Question &#xff1a;是否…

java第二部分项目_Java_第二次作业:项目构思与实现

写在最前&#xff1a;我我我我我我靠&#xff0c;以后再也不再ddl截止前1小时调试程序了&#xff01;之前在DDL前1小时修改程序&#xff0c;当我改完后&#xff0c;我想着&#xff0c;再把之前的测试样例跑一遍&#xff0c;如果都对就OK了。就在这时&#xff0c;问题出现了&…

java远程插件动态注册机制_Spring运行时动态注册bean的方法

在spring运行时&#xff0c;动态的添加bean,dapeng框架在解析xml的字段时&#xff0c;使用到了动态注册&#xff0c;注册了一个实现了FactoryBean类&#xff01;定义一个没有被Spring管理的Controllerpublic class UserController implements InitializingBean{private UserSer…

java变量用来干嘛_Java

一、Maven的简介1、Maven是什么&#xff1f;Apache Maven是一个软件项目管理的综合工具。基于项目对象模型(POM)的概念&#xff0c;提供了帮助管理构建、文档、报告、依赖、发布等方法&#xff0c;Maven简化和标准化项目建设过程。处理编译&#xff0c;分配&#xff0c;文档&am…

mysql 视图 数据相加_MySQL

查看安装路径ps -ef|grep mysql1&#xff0c;配置linux虚拟机&#xff0c;修改IP????? vim /etc/sysconfig/network-scripts/ifcfg-eth02&#xff0c;配置完网卡之后&#xff0c;执行清空命令3&#xff0c;reboot查看生产环境上传文件MySQL5.5编译方式安装过程参考连接&am…

mllib协同过滤 java实现_协同过滤(ALS)算法介绍及Spark MLlib调用实例(Scala/Java/Python)...

协同过滤算法介绍&#xff1a;协同过滤常被用于推荐系统。这类技术目标在于填充“用户&#xff0d;商品”联系矩阵中的缺失项。Spark.ml目前支持基于模型的协同过滤&#xff0c;其中用户和商品以少量的潜在因子来描述&#xff0c;用以预测缺失项。Spark.ml使用交替最小二乘(ALS…

java编程启蒙_程序设计入门—Java语言

第一周&#xff1a;做点计算1.1 第一个程序如何下载、安装Eclipse和JRE&#xff0c;并且简单介绍一下这个软件的几个主要部分&#xff1b;如何在Eclipse中编辑、编译和运行程序&#xff1b;详解第一个程序&#xff1a;程序框架、输出、出错怎么办&#xff1b;做点计算&#xff…

python中什么是关键字参数_Python中的关键字参数

关键字参数与函数调用有关。在函数调用中使用关键字参数时&#xff0c;调用者通过参数名称标识参数。由于Python解释器能够使用提供的关键字来将值与参数进行匹配&#xff0c;因此您可以跳过参数或将其乱序放置。您还可以通过以下方式对printme()函数进行关键字调用-示例#!/usr…

java 任意代码执行漏洞_php-fpm在nginx特定环境下的任意代码执行漏洞(CVE-2019-11043)...

目录0x01 漏洞介绍0x02 漏洞影响0x03 漏洞复现0x01 漏洞介绍在长亭科技举办的 Real World CTF 中&#xff0c;国外安全研究员 Andrew Danau 在解决一道 CTF 题目时发现&#xff0c;向目标服务器 URL 发送%0a符号时&#xff0c;服务返回异常&#xff0c;疑似存在漏洞。在nginx上…

c enum能像java一样吗_不一样的Java Enum

Emum是在Java5中引入的新特性&#xff0c;从那开始&#xff0c;它被广泛的用在不同的Java应用中&#xff0c;相比于C和C的Enum&#xff0c;Java的Enum功能更加强大。但是很多开发人员暂时还没意识到它的强大之处&#xff0c;在Enum的一些细节问题上把握的还不到位。Enum的特性及…

java se 9.0.4_jre 9下载(Java SE Runtime Environment)下载

JRE9官方下载是运行JAVA程序不可缺少的环境。JRE中由ClassLoader负责查找和加载程序引用到的类库&#xff0c;基础类库ClassLoader会到rt.jar中自动加载&#xff0c;其它的类库&#xff0c;ClassLoader在环境变量CLASSPATH指定的路径中搜索&#xff0c;按照先来先到的原则&…

php+数组存放文件名_php将数组存储为文本文件的三种方法

本篇文章主要介绍php将数组存储为文本文件的三种方法&#xff0c;感兴趣的朋友参考下&#xff0c;希望对大家有所帮助。(1)利用serialize 将数组序列化存储为文本文件&#xff0c;调用时候再使用unserialize 还原<?php $file./cache/phone.php;$arrayarray(color> array…

php 屏蔽ctrl c,ctrl+c用不了怎么回事

解决办法&#xff1a;首先在运行里输入clipbrd打开剪贴板查看器看看里面是什么东西如果是剪贴板卡死了的话重启可解决问题如果不是复制个别的东西还是那个那么需要杀毒了&#xff01;(可能是灰鸽子病毒&#xff0c;冲击、震荡、狙击等都有可能导致不能复制粘贴剪切)方法一&…

php生日计算年龄,php根据生日计算年龄的方法

摘要&#xff1a;本文实例讲述了php根据生日计算年龄的方法。分享给大家供大家参考。具体如下&#xff1a;<?php function birthday($birthday){$age strtotime($birthday);if($age false){return false;本文实例讲述了php根据生日计算年龄的方法。分享给大家供大家参考。…

jq php异步上传图片,php+jquery Ajax异步上传图片(ajaxSubmit)实例_PHP教程

$photo_typesarray(image/jpg, image/jpeg,image/png,image/pjpeg,image/gif,image/bmp,image/x-png);//定义上传格式$max_size700000; //上传照片大小限制,默认700k$photo_folder"upload/".date("Y")."/".date("m")."/".da…

solaris php,针对 Solaris 的安装提示

用户评论:[#1]ariedederde [2011-06-18 00:58:25]Install php on solaris express:pkg search phppart of output is e.g.pkg:/web/php-525.2.12-0.151.0.1pkg install php-52php binary installs in /usr/php/5.2/bin/php[#2]julie at baumler dot com [2006-12-28 21:22:35]T…

php ajax复选框是否选中的值,jquery-ajax - php+ajax分页时,checkbox复选框选中的问题...

目的&#xff1a;所有的数据实现分页显示&#xff0c;不是查询所有的数据&#xff0c;而是每次取固定的条数。而且在每页选中的数据ID都可以保存&#xff0c;一起提交选中的数据&#xff0c;做相应的操作。比如第一页选中2条&#xff0c;第二页选中3条&#xff0c;提交时是5条&…