当前位置: 首页 > news >正文

简述JVM

文章目录

  • JVM简介
  • JVM运行时数据区
    • 堆(线程共享)
    • 方法区/元空间/元数据区(线程共享)
    • 程序计数器
  • JVM类加载
    • 类加载过程
    • 双亲委派模型
  • 垃圾回收机制(GC)
    • 判断对象是否为垃圾
      • 判断是否被引用指向
    • 如何清理垃圾, 释放对象?

JVM简介

JVM 是 Java Virtual Machine 的简称, 意为Java虚拟机.

虚拟机是指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统。

JVM运行时数据区

也就是JVM的内存布局

在这里插入图片描述

堆(线程共享)

保存程序中创建的对象

方法区/元空间/元数据区(线程共享)

存放被JVM加载的类信息(类对象), 常量, 静态变量(static), 即时编译器编译后的代码等数据

存放方法的调用关系, 局部变量

程序计数器

记录了当前线程执行的下一条指令的内存地址


class Test {public int n = 20;public static int a = 10;
}
public class Main() {public static void main(String[] arg) {Test t = new Test();}
}

n是普通的成员变量, 就包含在new的对象的内部, 存放在堆上

a是一个静态成员变量, 包含在类对象中, 存放在方法区中

t是一个局部变量, 存放在栈上

new Test()这个对象是保存在堆上的

栈上的t保存了堆上的new Test()的内存地址

JVM类加载

Java程序一开始是一个.java文件, 通过javac编译成.class文件, 运行java程序, JVM就会读取.class文件, 把文件的内容加载到内存中, 并构造成一个.class对象

类加载就是: 把类从硬盘文件加载到内存中.

类加载过程

流程:

  1. 加载: 找到.class文件, 打开文件, 并读取文件内容, 并且尝试解析格式

  2. 验证: 检查当前.class文件是否符合标准格式

  3. 准备: 给类对象分配内存. 分配出来的内存空间, 内容就是全0的值.

  4. 解析: 将常量池内的符号引用替换为直接引用的过程, 也就是初始化常量的过程. 初始化类对象中涉及到的一些字符串常量, 这些字符串常量在.class文件中已经存在, 直接读到内存中就行.

    • 符号引用: 偏移量. 在.class文件中不知道字符串真实的内存地址在哪, 只知道一个相对的偏移量, 知道字符串的内容在.class文件的哪个地方.
    • 直接引用: 真实的内存地址
  5. 初始化: 对类对象进行更具体的初始化操作. 初始化金泰城园, 执行静态代码块, 加载父类…


双亲委派模型

实则单亲.

JVM加载.class文件的时候, 需要用到"类加载器"模块.

JVM中自带了三个类加载器:

  • Bootstrap ClassLoader: 负责加载标准库中的类
  • Extension ClassLoader(父亲是Bootstrap ClassLoader): 负责加载JVM扩展的库
  • Application ClassLoader(父亲是Extension ClassLoader): 负责加载第三方库.

不是父类子类的继承关系, 而是对象里有一个parent引用指向 父 类加载器 实例

当接收到类加载请求时:

  • Application ClassLoader是类加载的入口, 不会立即就搜索第三方库的目录, 而是先把任务委派给父亲, 让父亲先尝试加载.
  • 到了Extension ClassLoader, 也不会立即搜索扩展库的目录, 把任务委派给父亲, 让父亲先尝试加载.
  • 到了Bootstrap ClassLoader, 也不会立即搜索扩展库的目录, 把任务委派给父亲, 但是他没有父亲, 就只能自己来搜索了. 如果找到了这个类, 就会进行后续的加载流程; 如果没有, 那么任务就会交付给孩子来解决.
  • 如果任务回到了Extension ClassLoader, 他就要搜索扩展库的目录, 如果找到了这个类, 就会进行后续的加载流程; 如果没有, 那么任务就会交付给孩子来解决.
  • 如果任务回到了Application ClassLoader, 他就要搜索第三方库的目录, 如果找到了这个类, 就会进行后续的加载流程; 如果没有, 那么就抛出异常.

这样做的目的: 明确类的优先级(标准库的类最优先加载, 扩展库其次, 第三方库最低)

标准库中有一个类java.lang.String, 如果我们自己也写了一个java.lang.String类

JVM始终是加载标准库里的类, 而不会加载到我们写的类, 这样便可以避免程序员的代码对标准库的代码产生负面影响


类加载的时机?(类似于懒汉模式, 用到了才加载)

  1. 构造了这个类的实例
  2. 使用了该类的静态方法, 静态属性
  3. 子类的加载会触发父类加载.

垃圾回收机制(GC)

对于程序计数器, 栈而言, 它的生命周期与相关的线程有关, 随线程生, 随线程灭, 并且这两个区域的内存分配和回收具有确定性, 因为当方法或者线程结束了, 内存就自然跟着线程回收了. 所以垃圾回收主要是回收堆和方法区这两个区域.

缺点: 消耗额外的系统资源, 消耗一定的时间, 可能有STW问题

垃圾回收是以对象为单位进行回收

垃圾回收的流程分为两步: 1. 判定对象是否为垃圾. 2. 释放对象的内存

判断对象是否为垃圾

一个对象, 如果在后续代码中不会被继续使用到了, 就可以视作是垃圾了

  • 不会被继续使用: 没有被任何引用指向

    public void test() {T t = new T();t.func();
    }
    test();
    

    调用方法test的时候, 局部变量t被创建, 当test方法执行完了之后, t自然销毁, 此时new T()就没有被引用指向了, 这个对象也就是垃圾了.

判断是否被引用指向

  1. 引用计数

    给这个对象里面安排一个计数器, 每次有引用指向它, 就把计数器+1, 每次引用被销毁, 计数器-1, 当计数器为0, 意味着该对象就是垃圾了

    class Test {//
    }
    Test t = new Test();//new Test()里的计数器为1
    Test t2 = t;//new Test()里的计数器为2
    Test t3 = t2;//new Test()里的计数器为3
    t = null;//new Test()里的计数器为2
    t2 = null;//new Test()里的计数器为1
    t3 = null;//new Test()里的计数器为0, 此时该对象为垃圾了
    

    该方法并非是JVM中使用的方案, Python和PHP的虚拟机GC采用的是此方案

    缺陷:

    • 空间利用率低, 浪费更多的内存空间

    • 可能存在循环引用的问题, 导致对象不能正确识别为垃圾.

      class Test {public Test t;
      }
      Test a = new Test();//计数器为1
      Test b = new Test();//计数器为1
      a.t = b;//计数器为2
      b.t = a;//计数器为2
      a = null;//计数器为1
      b = null;//计数器为1
      

      在这里插入图片描述

      此时这两个对象的引用计数不为0, 不能被当做垃圾. 与此同时, 一想要使用对象1, 就需要访问对象2. 要想使用对象2, 就得先访问到对象1…这就是循环引用

  2. 可达性分析(JVM使用的方案)

    JVM首先会从现有代码中的能直接访问到的对象出发, 尝试便利所有能访问的对象, 只要对象能访问到, 就会标记成"可达", 完成整个遍历之后, 不可达的对象, 就相当于是垃圾了.

    这样的操作没有额外的空间开销, 但是消耗了更多的时间.

    那些是能直接访问到的对象呢?

    这些对象又被称为gc roots.

    1. 栈上的局部变量.
    2. 常量池里的引用
    3. 方法区中类静态属性引用的对象
    4. 本地方法栈中 JNI(Native方法)引用的对象

    代码执行过程中, 一个对象是否是垃圾, 往往是动态变化的(之前不是垃圾, 现在是垃圾了), 所以可达性分析的扫描是持续的周期性的

如何清理垃圾, 释放对象?

  1. 标记清除: 被标记为垃圾的对象直接清除.

    弊端: 申请内存的时候, 都是申请的连续的空间, 直接释放会导致内存的碎片化, 会破环原有的连续性, 可能会导致有内存, 但是申请不了.

  2. 复制算法: 通过冗余的内存空间, 把有效的对象复制到另一部分空间, 避免内存碎片.

    把一个内存分成两份, 一份使用, 一份等待有效对象被复制过来.

    弊端: 如果复制的对象多, 开销会很大, 而且内存利用率也不高, 相当于浪费了一般的内存.

  3. 标记整理: 类似于顺序表的删除元素操作.

    弊端: 这样的方式虽然解决了复制算法内存利用率低的问题, 但是搬运对象的成本也比较高.

  4. 分代回收: 采用分治的思想, 进行代的划分, 把不同生命周期的对象放在不同代上, 不同代上采用最适合它的垃圾回收方式进行回收.

    Java的对象大体分为两类: 1. 生命周期很长的; 2.生命周期很短的

    不同的对象的生命周期是不一样的. 因此, 不同生命周期的对象可以采取不同的收集方式, 以便提高回收效率.

    如何分代?

    JVM根据对象存活的周期(GC周期性扫描)不同, 把对内存划分了2块, 为新生代老年代.


    新生代又分为伊甸区(Eden)和幸存区(Survivor).

    伊甸区占大部分内存, 这里存储的对象生命周期都很短. 经过一次GC后, 存活下来的对象就会通过复制算法复制到幸存区.

    幸存区是两块大小相等的内存区域, 每次只用一块, 如果这里的对象经过GC后存货, 会继续被复制到另一块幸存区, 如此往复.如果一个对象在幸存区里经过了很多轮GC还存活, 证明它的生命周期很长, 那么它就会被复制到老年代.


    老年代的GC频率比新生代要低. 这里清理垃圾的策略是标记整理

    如果一个对象的体积很大, 那么他会直接进入老年代, 因为这样的对象不适合进行复制

相关文章:

简述JVM

文章目录 JVM简介JVM运行时数据区堆(线程共享)方法区/元空间/元数据区(线程共享)栈程序计数器 JVM类加载类加载过程双亲委派模型 垃圾回收机制(GC)判断对象是否为垃圾判断是否被引用指向 如何清理垃圾, 释放对象? JVM简介 JVM 是 Java Virtual Machine 的简称, 意为Java虚拟机…...

【多线程面试题 六】、 如何实现线程同步?

文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。 面试官: 如何实现线程同步&…...

地面文物古迹保护方案,用科技为文物古迹撑起“智慧伞”

一、行业背景 当前,文物保护单位的安防系统现状存在各种管理弊端,安防系统没有统一的平台,系统功能不足、建设标准不同,产品和技术多样,导致各系统独立,无法联动,形成了“信息孤岛”。地面文物…...

k8s之Flannel网络插件安装提示forbidden无权限

一、问题描述 在安装k8s的网络插件时,提示如下信息,各种forbidden无权限 [rootzzyk8s01 scripts]# kubectl apply -f kube-flannel.yml Error from server (Forbidden): error when retrieving current configuration of: Resource: "policy/v1b…...

在微信小程序云开发中引入Vant Weapp组件库

介绍 Vant 是一个轻量、可靠的移动端组件库,于 2017 年开源。 目前 Vant 官方提供了 Vue 2 版本、Vue 3 版本和微信小程序版本,并由社区团队维护 React 版本和支付宝小程序版本。 介绍 - Vant Weapp (youzan.github.io) Vant Weapp需要安装 node.js&…...

Vue+ElementUI项目打包部署到Ubuntu服务器中

1、修改config/index.js中的assetsPublicPath: /,修改为assetsPublicPath: ./ assetsPublicPath: ./2、在build/utils.js中增加publicPath: ../../ publicPath: ../../3、打开终端,在根目录下执行npm run build进行打包,打包成功后会生成dist npm run…...

面试题收集——Java基础部分(一)

1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?   可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致。 2、Java有没有goto?   java中的保留字…...

Vue中this指向问题

文章目录 1 由Vue管理的函数2 不被Vue管理的函数3 总结 1 由Vue管理的函数 computed 计算属性watch 监视属性filters (Vue3中已弃用且不再支持) 过滤器methods 上述属性里配置的函数this指向Vue实例,不要采用箭头函数写法,因为箭头函数没有自己的this对…...

【iPad已停用】解锁教程

iPad多次输错密码时,会自动锁定并停用,这时候你可以使用iTuens或Tenorshare进行解锁。 一、使用iTunes解锁 下载并安装iTunes 使用数据线将iPad连接上电脑 让iPad进入恢复模式,同时安装iPad电源键和Home键,直到Logo出现也不要松…...

python不调用heapq库 实现大顶堆,小顶堆

参考了博客,并对其进行了堆的push() 和 降序排序的补充 【精选】图解堆排序及其Python实现_python 实现小顶堆-CSDN博客 目录 大顶堆 调用结果展示: 小顶堆: 调用结果展示: 此结果与调用heapq库中的heapify(arr)函数等效 …...

STM32F4X SDIO(二) SDIO协议

上一节简单介绍了SD卡的分类,本节将会介绍SD卡的通信协议,也就是SDIO协议。 STM32F4X SDIO(二)SDIO协议 SD 卡管脚和寄存器SD卡管脚分布SD卡通信协议SD卡寄存器SD卡内部结构 SDIO总线SDIO总线拓扑SDIO总线协议SDIO协议的基本结构…...

设计模式--7个原则

单一职责原则:一个类负责一项职责。 里氏替换原则:继承与派生的规则。 依赖倒置原则:高层模块不应该依赖基层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。即针对接口编程&#xff0…...

AltiumDesigner原理图编译错误报告信息解释

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、ViolationsAssociated with Buses 有关总线电⽓错误的各类型(共 12 项)二、ViolationsAssociated Components 有关元件符号电⽓错误…...

使用 Visual Studio Code 编写 TypeScript程序

安装 TypeScript 首先,确保你已经安装了 TypeScript,如果没有安装,请参考https://blog.csdn.net/David_house/article/details/134077973?spm1001.2014.3001.5502进行安装 创建 新建一个文件夹,用vs code打开,在文…...

科大讯飞发布讯飞星火 3.0;开源AI的现状

🚀 科大讯飞发布讯飞星火 3.0,综合能力超越ChatGPT(非GPT-4版) 摘要:科大讯飞在2023全球1024开发者节上宣布讯飞星火 3.0正式发布,号称综合能力已超越ChatGPT。据介绍,星火认知大模型 V3.0在文…...

公网远程访问macOS本地web服务器

# 公网访问macOS本地web服务器【内网穿透】 文章目录 1. 启动Apache服务器2. 公网访问本地web服务2.1 本地安装配置cpolar2.2 创建隧道2.3 测试访问公网地址3. 配置固定二级子域名3.1 保留一个二级子域名3.2 配置二级子域名4. 测试访问公网固定二级子域名 以macOS自带的Apache…...

windows 安装小乌龟

这是什么 这里简单描述一下在windows上如何安装GIT代码管理工具和使用小乌龟版本来调用GIT,并且配置一下git相关信息,可以使用小乌龟来操作代码。也有一些常规git使用方法。 需要的资源 Git-2.42.0-64-bit.exe(这个是git代码管理工具&…...

toon boom harmony基础

以下都是tbh快捷键使用,或者一些常用功能介绍 1、在节点视图中,按回车可直接弹出节点库搜索框 2、中心线编辑器 只能编辑用笔刷画出来的线条,铅笔画出来的线条无法编辑。 3、镜头标记 1 右键箭头方向,可弹出下拉,&am…...

JPA联合主键

​ 在实际工作中,我们会经常遇到联合主键的情况,所以我用简单例子列举JPA两种实现联合主键的方式。 1、如何通过IdClass 实现联合主键 第一步:新建一个UserInfoID类,里面是联合主键 Data Builder NoArgsConstructor AllArgsConstructor pu…...

水性杨花:揭秘CSS响应式界面设计,让内容灵活自如,犹如水之变幻

🎬 江城开朗的豌豆:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 📝 个人网站 :《 江城开朗的豌豆🫛 》 ⛺️ 生活的理想,就是为了理想的生活 ! 目录 ⭐ 专栏简介 📘 文章引言 一、是…...

fio performance test

fio参数解释 可以使用fio -help查看每个参数,具体的参数左右可以在官网查看how to文档,如下为几个常见的参数描述 filename/dev/emcpowerb 支持文件系统或者裸设备,-filename/dev/sda2或-filename/dev/sdb 或 -filename/dev/nvme0n1direct…...

DevOps持续集成-Jenkins(1)

文章目录 DevOpsDevOps概述Code阶段工具(centos7-gitlab主机)Windows下安装Git(作用是:使我们可以上传代码到GitLab)Linux下安装GitLab⭐(作用是:运行一个GitLab接收代码)环境准备先…...

Pytorch代码入门学习之分类任务(二):定义数据集

一、导包 import torch import torchvision import torchvision.transforms as transforms 二、下载数据集 2.1 代码展示 # 定义数据加载进来后的初始化操作: transform transforms.Compose([# 张量转换:transforms.ToTensor(),# 归一化操作&#x…...

oracle 里常用的一些 create insert update table

1、获得数据库里某个指定的库 SELECT COUNT(*) FROM ALL_TABLES ut WHERE ut.OWNERTJFX AND ut.TABLE_NAME CUR_TIME_BILL; 2、创建一个表,里面的数据可以从一个已存在的表里转移过来 CREATE TABLE temptable AS SELECT * FROM old_tbName //使用现有的表创建一…...

从Mysql架构看一条查询sql的执行过程

1. 通信协议 我们的程序或者工具要操作数据库,第一步要做什么事情? 跟数据库建立连接。 首先,MySQL必须要运行一个服务,监听默认的3306端口。在我们开发系统跟第三方对接的时候,必须要弄清楚的有两件事。 第一个就是通…...

Linux系统下DHCP服务安装部署和使用实例详解(蜜罐)

目录 一、概述 二、具体配置如下: 一、概述 DHCP :动态主机设置协议(英语:Dynamic Host Configuration Protocol,DHCP)是一个局域网的网络协议,使用UDP协议工作,主要有两个用途&…...

模数转换器-ADC基础

文章目录 一、ADC是什么二、ADC处理采样保持量化编码三、ADC采样的重要参数:测量范围:分辨率(Resolution):精度:采样时间:采样率(Sampling Rate):信噪比(Signal-to-Noise Ratio, SNR):转换时间:一、ADC是什么 ADC(Analog-to-Digital Converter):模拟数字转换器…...

Linux:【1】Linux中的文件权限概念和相关命令

Linux:【1】Linux中的文件权限概念和相关命令 1、什么是文件权限?1.1、文件权限的表示方式 2、理解文件权限2.1、用户权限2.2、组权限2.3、其他权限 3、设置文件权限3.1、chmod 命令3.2、权限符号表示法3.3、权限数字表示法 4、查看文件权限4.1、ls 命令…...

JS实用小计

1.如何创建一个数组大小为100,每个值都为0的数组 // 方法一: Array(100).fill(0);// 方法二: // 注: 如果直接使用 map,会出现稀疏数组 Array.from(Array(100), (x) > 0);// 方法二变体: Array.from({ length: 100 }, (x) > 0); 2.如何逆序一个字…...

Android---Bitmap详解

每一个 Android App 中都会使用到 Bitmap,它也是程序中内存消耗的大户,当 Bitmap 使用内存超过可用空间,则会报 OOM。 Bitmap 占用内存分析 Bitmap 用来描述一张图片的长、宽、颜色等信息,可用使用 BitmapFactory 来将某一路径下…...