Direct Buffer和flip方法 和垃圾收集_buffer isdirect()-程序员宅基地

技术标签: Java io  

DirectBuffer和MappedByteBuffer

DirectBuffer : 在 Buffer 的方法定义中,有一个 isDirect() 方法,返回当前方法是否是 Direct 类型。这是 Java 提供的堆外 Buffer。可以使用 allocateDirect 方法直接创建。如:ByteBuffer.allocateDirect(1024);
MappedByteBuffer:它将文件按照指定大小直接映射为内存区域,当程序访问这个内存区域时,将直接操作这块文件数据,省去了将数据从内核空间向用户空间传输的损耗。我们可以使用 FileChannel.map 创建 MappedByteBuffer,它本质上也是种 Direct Buffer。

为甚需要directBuffer

在实际使用中,Java 会尽量对 Direct Buffer 仅作本地 IO 操作,对于很大数据量的 IO 密集型操作,可能会带来很大的性能优势,因为:
Direct Buffer 在生命周期内内存地址都不会再做改变,进而内核可以直接安全地对其访问,很多 IO 操作会很高效。
Direct Buffer 避免了堆内对象需要的额外的维护工作,提高了效率。

典型的nio中,使用了directBuffer可以避免用户空间和内核空间内存的拷贝,提升性能。

合理使用directBuffer:

但是,高效背后也是高成本。Direct Buffer 在创建和销毁过程中,都会比一般的 Buffer 增加部分开销,所以通常应该用于长期使用、数据量较大的场景。并且可以使用buffer池。可以参考netty的使用

directBuffer实例代码与flip方法

    public static boolean directCopyFile(FileInputStream fis, FileOutputStream fos) throws IOException {
        FileChannel srcFileChannel = fis.getChannel();
        FileChannel targetFileChannel = fos.getChannel();
        //间接获取ByteBuffer
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);
        while(true) {
            byteBuffer.clear();
            int readByte = srcFileChannel.read(byteBuffer);
            if(readByte == -1) {
                break;
            }
            byteBuffer.flip();
            targetFileChannel.write(byteBuffer);
        }
        return true;
    }

buffer中的flip方法涉及到bufer中的Capacity,Position和Limit三个概念。
Capacity在读写模式下都是固定的,就是我们分配的缓冲大小;
Position类似于读写指针,表示当前读(写)到什么位置
Limit在写模式下表示最多能写入多少数据,在读模式下表示最多能读多少数据,初始和Capacity相同。

在写模式下调用flip方法,那么limit就设置为了position当前的值(即当前写了多少数据),postion会被置为0,以表示读操作从缓存的头开始读。也就是说调用flip之后,读写指针指到缓存头部,并且设置了最多只能读出之前写入的数据长度(而不是整个缓存的容量大小)。

directBuffer的垃圾回收

Direct Buffer 因为不在堆上,所以 Xmx 参数对它无效,可以使用下面的代码设置堆外内存的大小:
-XX:MaxDirectMemorySize=512M
从参数设置和内存问题排查来看,我们在设置 JVM 需要的内存时,如果用到了堆外内存,还应考虑堆外内存的开销。而出现了 OOM 问题时,也应该考虑是否是堆外内存不够的可能性。

对于 Direct Buffer 的回收,可以考虑:

在应用程序中,显式调用 System.gc() 来强制触发。
另一种思路是,在大量使用 Direct Buffer 的部分框架中,框架会自己在程序中调用释放方法,Netty 就是这么做的。
重复使用 Direct Buffer,而不是每次需要再创建,用完立刻销毁。

跟踪诊断 Direct Buffer 的内存占用的方法
在普通的垃圾收集日志中,并不包含 Direct Buffer 等信息,所以 Direct Buffer 的内存诊断是个比较头疼的问题。在 java 8 以后,我们可以使用 Native Memory Tracking (NMT) 来诊断,在启动程序时加上下面的参数可以激活 NMT,但是会导致 JVM 出现 5%~10% 的性能下降:

-XX:NativeMemoryTracking={summary|detail}
开启 NMT 后,就可以通过下面的命令进行交互式对比:

// 打印 NMT 信息
jcmd <pid> VM.native_memory detail 
// 进行 baseline,以对比分配内存变化
jcmd <pid> VM.native_memory baseline
// 进行 baseline,以对比分配内存变化
jcmd <pid> VM.native_memory detail.diff

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/h2604396739/article/details/101361702

智能推荐

记一次idea 打包时出现的错误 Discovered module-info.class. Shading will break its strong encapsulation.-程序员宅基地

文章浏览阅读1.5k次。需要在 pom 文件中加入这个依赖。注意,版本号要修改,不然会报错,我之前用的是 3.0.1 有报错,不知道其他版本会不会报错,调成这个版本后就不报错了。1、当打一个 module 下的包时,本项目下的其他module也不能有错误。放到maven中的项目下会显示具体报的哪个错,然后去修改就行。2、当出现下面的错误时。......_discovered module-info.class. shading will break its strong encapsulation.

Tensorrt学习笔记_trtlite安装-程序员宅基地

文章浏览阅读286次。Tensorrt学习笔记@[TOC](Tensorrt学习笔记)1. tensorflow、tensorrt数据格式2. end_to_end_tensorflow_mnist3. 使用tensorrt创建自定义网络4. 使用python接口导入Tensorflow模型5. 在python中序列化引擎1. tensorflow、tensorrt数据格式tensorflowtemsorrtNWHCNCWHN:batch-sizeW:widthH:heightC:通道2._trtlite安装

springboot+redis实现延迟队列(内含Redisson版本)_spring boot redis延时队列不消费-程序员宅基地

文章浏览阅读1.8k次。原理:开启一个守护线程对消息进行轮询消费,利用zset的有序性,将到达过期时间的消息去除,不能的实现类处理不同的业务。2:延迟队列类3:延迟消息消费类 开启一个线程进行消息的消费4:示例2:延时消息处理器接口3:示例三:项目demo地址......_spring boot redis延时队列不消费

c语言编程花朵,C语言花朵代码.doc-程序员宅基地

文章浏览阅读2.9k次。C语言花朵代码. C语言——绘画花朵代码部分#include #include #define PI 3 LRESULT CALLBACK WindowProcedure ( HWND, UINT, WPARAM, LPARAM );void OnPaint ( HDC ); void DrawLine ( HDC, int, int, int, int );void DrawFlower (..._用c语言画一朵花

x265中codeIntraLumaQT()分析-程序员宅基地

文章浏览阅读954次。x265中codeIntraLumaQT()分析_codeintralumaqt

KaliLinux-剪切板攻击-PasteJacker工具的安装-程序员宅基地

文章浏览阅读2.7k次,点赞2次,收藏20次。在kali中安装 pastejacker 和 pip下载安装 pip下载 pipwget https://bootstrap.pypa.io/get-pip.pypastejacker我安装的时候用的是 python3 安装的所有它会在 python3.9 文件夹下/usr/local/lib/python3.9/dist-packages/PasteJacker/Core这个目录下有一个 vim updater.py..._pastejacker

随便推点

SRS源码分析-协程相关类_srs协程学习-程序员宅基地

文章浏览阅读3.2k次。SRS中使用协程库state-thread(ST), 在使用时对其进行了封装,保证使用方便。这种封装方法和使用thread库比较类似。在SRS中,st封装所在的文件为:srs_app_ast.hpp/cppISrsCoroutineHandlerHandle接口实现如下,每一个需要使用ST-coroutine的类都需要实现这个接口。这个接口中有一个cycle()函数,在具体的类中执行任务以及..._srs协程学习

Golang Cobra Command详解(三)-程序员宅基地

文章浏览阅读3.3k次。基本上所有命令相关的功能都定义在Command结构体中type Command struct { // Use 表示用一句话来描述这个命令作用,这段话的第一个单词会被作为这个命令的名称 // 这个设置在子命令中生效,对于根命令则没有意义 Use string // Alias 可以用来给子命令定义别名,除了使用 Use 中的第一个单词作为子命令外,你还可以使用这个 Alias // 里面定义的任何一个名称作为子命令名称 Aliases []string // SuggestFor.._cobra command

c++ string使用详解_string is_initialized c++-程序员宅基地

文章浏览阅读1.4k次。之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必担心内存是否足够、字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下(甚至是100%)的需要。我们可以用 = 进行赋值操作,== 进行比较,+ 做串联(是不是很简单?)。我们尽可以把它看成是C++的基本数据类型。string ( );string ( con_string is_initialized c++

EMUI11半Q半鸿蒙,华为EMUI11系统尝鲜:距离鸿蒙更近了 三大新功能开启“高玩模式”...-程序员宅基地

文章浏览阅读66次。科客点评:这次的EMUI 11偏重针对了AOD、多任务以及多屏协同进行了升级,多这些功能比较看重的花粉可以选择尝鲜升级。日前,华为正式发布了EMUI 11,随即华为也开放了对部分机型的Beta升级。我们也为手中的华为P40进行了升级,带来了这次的上手体验。整体来说,EMUI 11强化了不少细节,好比更多选择的AOD和更连贯的动画效果,各位花粉不妨先相识一下。在AOD息屏显示上,EMUI 11提供了..._半鸿蒙

点乘和叉乘_点乘 叉乘 c#-程序员宅基地

文章浏览阅读883次。点乘判断角度,叉乘判断方向Vector3.Dot(transform.forward, target.position-transform.position)返回值为正时,目标在自己的前方,反之在自己的后方Vector3.Cross(transform.forward, target.position-transform.position).y返回值为正时,目标在自己的右方,反之在..._点乘 叉乘 c#

re.sub()基本用法_re.sub函数-程序员宅基地

文章浏览阅读1.9w次,点赞2次,收藏18次。re.sub()re=regular expression(正则表达式)sub=substitute(替换);re.sub是个正则表达式替换函数,用来实现通过正则表达式,实现比普通字符串的replace更加强大的替换功能;str.replace(“aaa”, “bbb”):将字符串str中的“aaa”替换为“bbb”例子:str="sajhaskdhj111sjh111dksd33..._re.sub函数

推荐文章

热门文章

相关标签