Java直接内存

直接内存如何使用

直接上代码,代码中有注释【对直接内存的分配以及释放】进行说明。

package cn.ordinary.util.io.file;import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.*;
import java.util.ArrayList;
import java.util.List;/*** @Date 2024/3/14* @Author sh**/
public class FileUtils {/*** 读取文件内容。** @param filePath 文件路径 + 文件名* @param charset  文件编码,默认使用 StandardCharsets.UTF_8* @throws FileNotFoundException 如果文件不存在* @throws IOException           如果读取文件发生错误*/public static StringBuilder read(String filePath, Charset charset)throws Exception {try (RandomAccessFile file = new RandomAccessFile(filePath, "r");FileChannel fileChannel = file.getChannel()) {/*** 1). 直接内存使用*  ① allocate()方法:*      这个方法会分配一个新的 非直接缓冲区。*      非直接缓冲区的内容位于 Java堆内存中,这意味着它受到垃圾回收器的影响。*  ② allocateDirect()方法:*      这个方法会分配一个新的 直接缓冲区。*      直接缓冲区的内容位于 操作系统的本地内存中(具体的来说,应该是在 java8内存结构中本地内存中的直接内存),*    而不是 Java堆内存中,所以它不受垃圾回收的影响。*      直接缓冲区可以提供更高的 I/O性能,因为对于本地 I/O操作而言,它不需要额外的内存复制操作(Java堆 和 本地内存 之间的数据复制)。* 2). 缓冲区预分配*  ① ByteBuffer 的容量最好不要是固定值。因为,在处理大文件的时候,可能需要多个这样的缓冲区来装载整个文件的内容。*  ② 使用 StringBuilder 累加文件内容是很高效的,比 String 拼接在循环冲更加高效。*      但是,在处理大文件的时候,capacity 的大小可能需要动态调整,或者根据文件的实际大小预先分配足够的空间,避免多次扩容带来的开销。*  综述,对于大文件,提前知道文件大小并且预分配 ByteBuffer和StringBuilder 的大小能显著提高性能,减少内存重新分配的次数。*/// 1- 创建一个 ByteBuffer(字节缓冲区),用于存放读取到的数据// 获取文件大小long fileSize = file.length();// 根据文件大小动态分配 ByteBuffer 的容量int capacity = ((int) Math.min(fileSize, Integer.MAX_VALUE));// 方式一:使用【非直接】字节缓冲区//ByteBuffer buffer = ByteBuffer.allocate(capacity);// 方式二:使用【直接】字节缓冲区ByteBuffer buffer = ByteBuffer.allocateDirect(capacity);// 2- 创建一个 utf8 的 CharsetDecoderif (null == charset) {charset = StandardCharsets.UTF_8;}CharsetDecoder decoder = charset.newDecoder();// 3- 读取数据到 buffer// 将读取到的内容存放到 StringBuilderStringBuilder content = new StringBuilder((int) fileSize);while (fileChannel.read(buffer) != -1) {// 切换到读模式,准备读取数据buffer.flip();// 使用 指定字符集 解码 ByteBuffer 到 CharBuffer,再转换为 Stringcontent.append(decoder.decode(buffer));// 清空缓冲区,准备下一次读取buffer.clear();}/*** 显示的释放 直接缓冲区占用的堆外内存。** 通过ByteBuffer.allocateDirect()分配的直接缓冲区(Direct Buffer)使用的是JVM堆外内存。* 与传统的堆内存不同,直接缓冲区不受Java垃圾回收器(GC)的直接管理,但是它们仍然会被间接地管理。** 直接缓冲区 与 一个Java对象关联(即ByteBuffer对象),该对象处于JVM的管理之下。* 当这个Java对象变得不可达时(即没有任何引用指向它),垃圾回收器可以对其进行垃圾回收。但是,这种方式并不是立即释放内存,而是要等到垃圾收集器运行时才会进行。* 在垃圾回收过程中,可以通过对象的清理(finalization)机制或者Java 9引入的Cleaner类来释放直接缓冲区占用的堆外内存。** 依赖于垃圾回收来回收直接缓冲区的内存可能会存在延迟,因为垃圾回收器无法直接感知堆外内存的压力。* 因此,如果快速和频繁地分配大量的直接缓冲区,可能会导致内存耗尽,特别是在有限的堆外内存资源的情况下。* 为了更好地管理直接缓冲区的堆外内存,可以使用 Cleaner 类显示的释放直接缓冲区占用的堆外内存。*/cleanDirectMemory(buffer);// 返回读取到的文件内容return content;} catch (FileNotFoundException e) {// 抛出文件不存在的异常,便于调用者识别和处理文件不存在的情况。throw new FileNotFoundException("文件不存在: " + filePath);} catch (IOException e) {// 抛出IO异常,便于调用者识别和处理IO异常。throw new IOException("读取文件失败: " + filePath, e);}}/*** 显式释放直接缓冲区占用的内存** @param buffer 字节缓冲区(这里指的是 直接缓冲区,因为 非直接缓冲区 在 Java堆内存上,GC可以进行自动内存管理)*/private static void cleanDirectMemory(ByteBuffer buffer) throws Exception {if (null == buffer) {return;}// 下面是 jdk8及之前的写法。从 Java9开始,推荐的释放直接缓冲区内存的方式是使用 sun.misc.Unsafe 类或者使用 java.lang.ref.Cleaner 类。try {// 调用 ByteBuffer 的 cleaner()方法 获取 CleanerMethod cleanerMethod = buffer.getClass().getMethod("cleaner");cleanerMethod.setAccessible(true);Object cleaner = cleanerMethod.invoke(buffer);// 调用 Cleaner 的 clean()方法 来显示的释放 直接缓冲区占用的 堆外内存(这里指的是 本地内存中的直接内存)。Method cleanMethod = cleaner.getClass().getMethod("clean");cleanMethod.setAccessible(true);cleanMethod.invoke(cleaner);} catch (Exception e) {throw new Exception("释放接缓冲区占用的堆外内存失败", e);}}}

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

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

相关文章

js一些底层

简介: JavaScript 是一种高级编程语言,通常在网页开发中用于前端和后端开发。JavaScript 的底层实现是浏览器或服务器上的 JavaScript 引擎。不同的引擎可能有不同的底层实现,但它们都有一个共同的目标,即执行 JavaScript 代码。 JavaScript …

MySQL中什么是分区表?列举几个适合使用分区表的场景。

MySQL中的分区表是一种数据库设计技术,它将一个大表物理地分割成多个较小的部分,这些部分被称为分区。虽然从逻辑上看,分区表仍然像一个单独的表,但在物理层面,每个分区都是存储在一个独立的文件上,可以位于…

ARM的三个按键实验

main.c #include "key_inc.h"//封装延时函数void delay(int ms){int i,j;for(i0;i<ms;i){for(j0;j<2000;j){}}}int main(){//按键中断初始化key1_it_config();key2_it_config();key3_it_config();while(1){printf("in main pro\n");delay(1000);}re…

Android中的onConfigurationChanged的使用

一.什么时候调用&#xff1a; 设备配置发生变化的时候调用&#xff0c;比如&#xff1a;内外屏切换、屏幕方向&#xff08;orientation&#xff09;、键盘状态&#xff08;keyboard&#xff09;、语言环境&#xff08;locale&#xff09;、屏幕布局&#xff08;screenlayout&a…

[金三银四] 操作系统上下文切换系列

图源&#xff1a; https://zhuanlan.zhihu.com/p/540717796 文章目录 2.11 cpu 的上下文切换2.12 协程的上下文切换2.13 线程的上下文切换2.14 进程的上下文切换2.15 中断上下文切换2.16 什么时候会发生进程的上下文切换2.17 什么时候会发生线程的上下文切换2.18 什么时候会发生…

Spring AOP失效的场景

Spring AOP其实是通过动态代理实现的,那么今天要聊的这个问题就是设想什么情况不能使用动态代理,这个问题其实跟Spring事务失效的场景差不多 内部类调用 首先就是类内部的调用&#xff0c;比如一些私有方法调用&#xff0c;内部类调用&#xff0c;以及同一个类中方法的自调用…

前缀和(一)

前缀和 一维前缀和数组 假设有一个数组为a [ n ] , 另一个数组为s [ n ] . 其中 s [ j ] a[1] a[ 2 ] ......a[ j-1] a [ j ] 。--->s[ j ]表示a数组从第一个元素到第 j 个元素之和&#xff0c;那么我们则就称 s 数组为前缀和数组 例题&#xff1a;前缀和 链接&#xff1a;…

vue v-if v-show 区别

Vue中的v-if和v-show都用于控制元素的显示和隐藏&#xff0c;但它们之间存在一些关键的区别。 渲染方式&#xff1a;v-if是“惰性”的&#xff0c;这意味着在条件为假时&#xff0c;相关的组件或元素的所有事件监听器和子组件都会被销毁&#xff0c;不会渲染到DOM中。只有当条…

遥感原理与应用—绪论

一、关于基本概念与对应的英文 遥感&#xff1a;Remote Sensing 遥测&#xff1a;Telemetry&#xff0c;对被测物体某些运动参数和性质进行远距离测量的技术&#xff0c;分为接触测量与非接触测量&#xff0c;对于RS的概念&#xff0c;遥测探测的目标显得狭隘了一些&#xff…

AI女朋友 -- 一个傲娇女友,嘴上刻薄但内心关心你

文章目录 前言一、成果展示 1、ai女友2、留言板二、实现思路三、难点问题四、总结 前言 在免费API寻找过程中&#xff0c;发现了ai女友的接口&#xff0c;打算从这个接口入手&#xff0c;做出给人一种有女朋友的、温柔的、亲近的、容易给的感觉&#xff01; 一、成果展示 1、A…

Git bash获取ssh key

目录 1、获取密钥 2、查看密钥 3、在vs中向GitHub推送代码 4、重新向GitHub推送修改过的代码 1、获取密钥 指令&#xff1a;ssh-keygen -t rsa -C "邮箱地址" 连续按三次回车&#xff0c;直到出现类似以下界面&#xff1a; 2、查看密钥 路径&#xff1a;C:\U…

Kubernetes概念:工作负载:工作负载管理:2. ReplicaSet

ReplicaSet ReplicaSet 的目的是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。 因此&#xff0c;它通常用来保证给定数量的、完全相同的 Pod 的可用性。 ReplicaSet 的工作原理 ReplicaSet 是通过一组字段来定义的&#xff0c;包括一个用来识别可获得的 Pod 的集…

FreeCAD傻瓜教程之基准面的构建-在实体的表面上新建坐标、倾斜的平面、附加不同的台阶、旋转体等

目的&#xff1a;学会在已有模型的不同剖面上建立新的坐标系&#xff0c;并绘图&#xff1b;使得新图形仍然作为同一个零件实体的构件。 零、需求举例 在下列模型中&#xff0c;我们要在圆杆的顶部增加一个把手&#xff0c;如果点击圆杆顶部&#xff0c;则仅能在顶部圆形所在…

JVM虚拟机栈

虚拟机栈 虚拟机栈概述 栈是运行时的单位&#xff0c;而堆是存储的单位。 栈解决程序的运行问题&#xff0c;即程序如何执行&#xff0c;或者说如何处理数据。堆解决的是数据存储的问题&#xff0c;即数据怎么放&#xff0c;放在那儿。 虚拟机栈的基本内容 Java虚拟机栈 Java…

瑞吉外卖实战学习--登录功能的开发

登录功能的开发 前端1、创建实体类Employee和employee表进行映射,可以直接导入资料中提供的实体类1.1、字段名称对应上&#xff0c;有下划线的使用驼峰对应&#xff0c;因为在配置文件中进行了配置1.2、employee 文件 2、创建Controller、Service、Mapper2.1、Mapper文件2.2、定…

Windows复现SiamCAR代码遇到的报错与解决方法

一、环境基础 Windows10以上 已装Anaconda 支持GPU 已经gitclone:https://github.com/HonglinChu/SiamTrackers 二、遇到的报错 1. No module named pycocotools._mask 方案一&#xff1a;加载非常慢 conda install -c conda-forge pycocotools 方…

蓝桥杯竞赛规则及说明【C/C++】

第十五届蓝桥杯全国软件和信息技术专业人才大赛个人赛规则解析 一、组别划分 本次大赛C/C和Java两个语言分别设有四个组别:研究生组、大学A组、大学B组和大学C组。选手只能选择参加其中一个组别的竞赛,各组评奖独立进行。 组别资格对应如下: 研究生组:只限研究生参加大学A组…

vite打包配置基础

Vite&#xff1a;优化前端打包的利器 Vite&#xff08;法语意为“快速”&#xff09;是由 Vue.js 之父尤雨溪开发的一款现代化的前端构建工具&#xff0c;其设计目标是通过提供更快的冷启动速度、更高效的热更新和智能的按需编译打包机制&#xff0c;极大地提升前端开发体验。…

智慧物联-能源分析平台

物联能源分析平台是为了满足企业对能源管理和节能减排的需求而开发的一套在线平台。随着能源问题日益凸显&#xff0c;企业对能源的使用和管理面临着越来越大的挑战。因此&#xff0c;开发一个能够帮助企业实时监测、分析和优化能源消耗的平台变得尤为重要。 随着工业化和城市…