JVM篇:直接内存

直接内存

直接内存并不是JVM的内存结构,直接内存是操作系统的内存,Java本身并不能对操作系统的内存进行操作,而是通过调用本地方法。直接内存常用于NIO作为缓冲区存在,分配成本较高但是读写性能好,并且不受JVM内存回收管理

NIO与IO的区别

public class demo5 {
    private static final String From = "下载文件路径";
    private static final String TO = "保存文件路径";
    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) {
        io();
        directBuffer();
    }

    public static void io() {
        long start = System.nanoTime();//开始时间
        byte[] buf = new byte[_1MB];

        try {
            FileInputStream inputStream = new FileInputStream(From);
            FileOutputStream outputStream = new FileOutputStream(TO);
            while (true) {
                int len = inputStream.read(buf);
                if (len == -1) {
                    break;
                }
                outputStream.write(buf);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end = System.nanoTime();
        System.out.println(end - start);
    }

    //NIO
    public static void directBuffer() {
        long start = System.nanoTime();//开始时间
        try (FileChannel channel = new FileInputStream(From).getChannel();
             FileChannel to = new FileOutputStream(TO).getChannel()) {
            ByteBuffer buf = ByteBuffer.allocateDirect(_1MB);
            while (true) {
                int len = channel.read(buf);
                if (len == -1) {
                    break;
                }
                //flip()大概意思是记录当前的缓冲位置,下次读入缓冲区从保存的位置开始读取
                buf.flip();
                to.write(buf);
                buf.clear();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end = System.nanoTime();
        System.out.println(end - start);
    }
}

对同一个文件进行下载保存操作,使用IO要比NIO慢很多,这个时候就要看IO与NIO的实现原理了。

IO实现原理

Java在运行到读取文件时,由于Java本身不能对操作系统的内存进行读取,所以需要调用本地方法对操作系统内存进行操作(也就是上图CPU时间轴的System部分),操作系统需要从磁盘文件读取文件到系统的缓冲空间(保存的第一份),系统缓冲区再写入Java的缓冲区(程序中定义的byte数组充当缓冲区,相当于二次保存),然后本地方法调用结束,CPU再转换到Java程序去读取Java缓冲区保存。

NIO实现原理

NIO与IO的区别在于操作系统会分出一块直接内存,这块内存java可以直接访问到,省去了操作系统的缓冲区到Java缓冲区的部分。因此读写性能比较好。对应的代码为ByteBuffer.allocateDirect()

直接内存的回收原理

这是还未进行分配直接内存是内存占用比为47%。

public class demo6 {
    public static void main(String[] args) throws IOException {
        //使用直接内存并分配1G大小
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024 * 1024 * 1024);
        System.out.println("分配完成");
        System.in.read();
        //将引用置空,使其可以被回收
        byteBuffer = null;
        System.gc();
        System.out.println("释放完成");
        System.in.read();
    }
}

接下来观察内存占用比

加了1G的直接内存后,占比为54%接下来调用gc垃圾回收

可以看到内存恢复为47%,说明直接内存被释放,但是直接内存是不受GC回收管理的,为什么会被释放呢?

实际上释放直接内存是JVM自己完成的,由Java底层Unsafe类实现。简单模拟一下

public class demo7 {
    public static void main(String[] args) throws IOException {
        Unsafe unsafe = getUnsafe();
        //base是指分配的内存地址
        long base = unsafe.allocateMemory(1024 * 1024 * 1024);
        unsafe.setMemory(base,1024 * 1024 * 1024,(byte) 0);
        System.in.read();
        unsafe.freeMemory(base);
        System.in.read();
    }

    public static Unsafe getUnsafe() {
//        Unsafe unsafe = Unsafe.getUnsafe();
        //通过暴力反射拿到底层类对象Unsafe
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            Unsafe unsafe = (Unsafe) f.get(null);
            return unsafe;
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}

上面代码手动释放直接内存的片段执行结果和第一个例子结果完全相同。那么我们去看一下ByteBuffer.allocateDirect()方法源码

该方法创建了一个DirectByteBuffer类对象,接着查看对应源码。

    DirectByteBuffer(int cap) {                   // package-private

        super(-1, 0, cap, cap);
        boolean pa = VM.isDirectMemoryPageAligned();
        int ps = Bits.pageSize();
        long size = Math.max(1L, (long)cap + (pa ? ps : 0));
        Bits.reserveMemory(size, cap);

        long base = 0;
        try {
            base = unsafe.allocateMemory(size);
        } catch (OutOfMemoryError x) {
            Bits.unreserveMemory(size, cap);
            throw x;
        }
        unsafe.setMemory(base, size, (byte) 0);
        if (pa && (base % ps != 0)) {
            // Round up to page boundary
            address = base + ps - (base & (ps - 1));
        } else {
            address = base;
        }
        //之所以能被回收直接内存与Cleaner有直接关联
        cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
        att = null;
    }

Clearner类型在Java的类库中叫做虚引用类型,特点是虚引用所关联的对象被GC回收时,会自动触发create方法。在JVM中有一个单独线程监视虚引用对象的状态,如果关联对象被回收就会执行对应的run方法。

由这个构造方法可以看出来,从第9行开始,做了手动释放直接内存代码块相同的事情。都是调用Unsafe对象去分配内存空间,不同的是,它创建了一个Cleaner对象,并调用了create方法,查看这个方法参数Deallocator对象源码

可以看出来它实现了Runnable接口,相当于由其他线程去执行run方法而不是主线程。run方法中调用了Unsafe的freeMemory()方法释放内存。

总结就是:在客户端分配直接内存时,创建了一个Clearner对象与客户端对象相绑定,当客户端对象被垃圾回收时,就会执行虚引用监视线程中的任务线程由JVM释放直接内存。

禁用显式回收对直接内存的影响

所谓禁用显式回收就是在运行前添加的一个JVM参数-XX:+DisableExplicitGC,添加该参数后,在代码中程序员编写的System.gc()就无法生效(因为手动的gc操作是一个Full GC是一个耗时比较久的操作,因此在大多时候,等待程序自己进行gc即可,手动的GC会影响程序运行效率。)由于手动gc失效,那么在JVM内存充足的情况下,与之关联的对象即使为null也不会立即被回收,那么直接内存也无法释放。为了避免这个问题,我们可以在频繁操作直接内存时,通过调用Unsafe类中的freeMemory方法来手动释放直接内存。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

百度吉利合作造车生态,极越“智价比”能否带来科技平权?

文|AUTO芯球 作者|文泽 临近年关,车企迎来“降价潮”。为了获得更好的年终成绩单,包括上汽大众、比亚迪、长安汽车、智己汽车等20多家品牌推出了购车补贴、限时优惠等措施,优惠幅度最高近20万元。 在此背景下,新车发布一个多月…

【AI视野·今日Robot 机器人论文速览 第六十七期】Mon, 1 Jan 2024

AI视野今日CS.Robotics 机器人学论文速览 Mon, 1 Jan 2024 Totally 16 papers 👉上期速览✈更多精彩请移步主页 Daily Robotics Papers MURP: Multi-Agent Ultra-Wideband Relative Pose Estimation with Constrained Communications in 3D Environments Authors A…

【Bootstrap5学习 day12】

Bootstrap5 导航 Bootstrap5提供了一种简单快捷的方法来创建基本导航,它提供了非常灵活和优雅的选项卡和Pills等组件。Bootstrap5的所有导航组件,包括选项卡和Pillss,都通过基本的.nav类共享相同的基本标记和样式。 创建基本导航 要创建简单…

智云影院CMS程序PHP源码V3.0 无需数据库

本程序无需数据库,直接上传源码即可访问,(服务器或虚拟主机空间)都可以搭建使用!模板自适应端,浏览体验更佳!安装操作简单!无需繁琐的操作,即可快速拥有一个视频看片资源…

PC+Wap仿土巴兔装修报价器源码 PHP源码

核心功能: 业主自助预算计算:通过简洁的界面,业主可以输入装修需求,系统自动进行预算计算信息自动收集:系统自动收集业主的基本信息,如姓名、联系方式、房屋面积等一键发送报价:业主完成预算计…

排序算法——关于快速排序的详解

目录 1.基本思想 2.基本原理 2.1划分思想 2.2排序过程 (1)选择基准值 (2)分割过程(Partition) (3)递归排序 (4)合并过程 2.3具体实例 2.4实现代码 2.5关键要…

VMware ESXI 8 安装ipmitool 调整戴尔服务器风扇转速

本文内容适合ESXI 8版本安装ipmitool ,进行管理,已知的是8.0以上版本无法安装社区的vib.所以需要自己编译文件,7.0及之前的版本可以安装vib版本的ipmtools。 一、编译好的适用于esxi8的ipmitool下载 ipmitool下载 二、安装ipmitool 1、开…

DNs服务学习笔记

DNS:域名系统(英文:Domain Name System)是一个域名系统,是万维网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。类似于生活中的11…

Redis 教程

Redis 简介 Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。 Redis 与其他 key - value 缓存产品有以下三个特点: Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次…

Python 雷达图的绘制(极坐标图) (Matplotlib篇-14)

Python 雷达图的绘制(极坐标图) (Matplotlib篇-14)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹…

位移贴图还原电影3D角色

在线工具推荐: 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 位移贴图(Displacement Map)在电影制作中是一…

如何实现无人机识别功能

无人机识别算法可以基于不同的传感器和技术,结合多种方法进行实现。以下是一些常见的无人机识别算法和技术: 视觉识别: 图像处理: 使用计算机视觉技术对无人机图像进行处理,包括特征提取、目标检测和跟踪等。深度学习&…

算法第十一天-组合总和Ⅳ

组合总和Ⅳ 题目要求 解题思路 来自[负雪明烛] 题目有个明显的提示:求组合的个数,而不是每个组合。如果是要求出每个组合,那么必须使用回溯法,保存所有路径。但是如果是组合个数,一般都应该想到[动态规划]的解法。 直…

Maven 开发环境搭建

Maven介绍 Apahche 软件基金会(非营业的组织,把一些开源软件维护管理起来) maven apahce的一个开宇拿项目,是一个优秀的项目构建(管理工具) maven 管理项目的jar 以及jar与jar之间的依赖 maven 可以完成…

前端结合MQTT实现连接 订阅发送信息等操作 VUE3

MQTT客户端下载 使用测试 在我之前文章中 MQTT下载基础使用 下面记录一下前端使用的话的操作 1.安装 npm i mqtt引入 import * as mqtt from "mqtt/dist/mqtt.min"; //VUE3 import mqtt from mqtt //VUE2 一、MQTT协议中的方法 Connect。等待与服务器建立连接…

04set注入专题/简单类型/数组/List/Set/Map/空字符串/null/特殊符号

1.1注入外部Bean 在之前使用的案例就是注入外部Bean的方式。 <!-- class属性声明要管理哪个类中的对象 property标签的name是提示set方法名ref标签指明注入的bean的id--><bean id"userServiceBean" class"com.powernode.spring6.service.UserService…

leetcode:908. 最小差值 I

一、题目 二、函数原型 int smallestRangeI(int* nums, int numsSize, int k) 三、思路 本题题目有些绕口&#xff0c;但是无伤大雅。本质就是可以对数组中的每个元素进行加/减 k 的操作&#xff0c;然后求数组中的最大、最小元素的最小差值。 分为几种情况&#xff1a; …

C 语言编程软件 | Dev-C++ 的安装及使用

Hi&#xff0c;大家好&#xff0c;我是源于花海。本文主要了解 Dev-C 的安装及使用。Dev-C&#xff08;又称Dev-Cpp&#xff09;是Windows环境下的一个轻量级 C/C集成开发环境&#xff08;IDE&#xff09;。它集合了功能强大的源码编辑器、MingW64/TDM-GCC 编译器、GDB 调试器和…

【数据库原理】(10)数据定义功能

SQL 数据定义功能包括定义模式、定义表、定义索引和定义视图,其语句如表所示。 一.创建、删除模式 1.创建模式 (Create Schema) 用途&#xff1a;创建模式是为了在数据库中定义一个新的命名空间&#xff0c;它可以包含多个数据库对象。 语法&#xff1a; CREATE SCHEMA &…

万界星空科技MES系统中的设备管理模块

随时工厂数字化建设的大力推进&#xff0c;设备管理的效率得到了很大的提升&#xff0c;特别是作为机加工企业&#xff0c;设备是整个企业非常重要的核心资产。 MES系统主要包含了生产计划、生产过程管理、质量管理、物料管理、设备维护等多个模块&#xff0c;各个模块之间相互…