简述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频率比新生代要低. 这里清理垃圾的策略是标记整理

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

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

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

相关文章

VSCode:清理ipch缓存

VSCode使用了一段时间,发现有些变慢,电脑管家扫描后,提示“AppData\Local\Microsoft\vscode-cpptools\ipch”目录下有很多缓存文件可以清理。 查询了一下:C/C 扩展常见问题解答 (visualstudio.com) 该件夹内包含缓存的预编译头文…

kibana监控

采取方式 Elastic Agent :更完善的功能 Metricbeat:轻量级指标收集(采用) 传统收集方法:使用内部导出器收集指标,已不建议 安装 metricbeat Download Metricbeat • Ship Metrics to Elasticsearch | E…

基于Jenkins实现接口自动化持续集成

一、JOB项目配置 1、添加描述 可选选项可填可不填 2、限制项目的运行节点 节点中要有运行环境所需的配置 节点配置教程 3、源码管理 需要将脚本推送到远程仓库中 4、构建触发器 可以选择定时构建和轮询SCM 定时构建:根据设置的定时时间,自动执行定…

c++系列之vector类模拟实现

💗 💗 博客:小怡同学 💗 💗 个人简介:编程小萌新 💗 💗 如果博客对大家有用的话,请点赞关注再收藏 🌞 构造函数 vector() //_begin表示有效成员的开始 //_finish表示有效成员的大小…

python实现批量pdf转txt和word

文章目录 背景需求环境安装完整代码效果 背景需求 已经获取到了大量的pdf在download文件夹中,但是我需要的是txt文件和word文件~ 环境安装 pip install pdf2docx pdfminer.six完整代码 # pip install pdf2docx pdfminer.siximport os from pdf2docx …

idea 基础设置

1、设置 IDEA 主题 2、自动导包和优化多余的包 3、同一个包下的类,超过指定个数的时候,导包合并为* 4、显示行号 , 方法和方法间的分隔符: 5、忽略大小写,进行提示 6、多个类不隐藏,多行显示 7、设置默认的…

sys.dm_exec_requests中statement_start_offset与statement_end_offset

文章目录 1.缘起2.根因3.示例4.附录 1.缘起 mssql中查早阻塞与及其相关联的sql时,遇到如下内容,故记录一下, substring(dest_blocked.text,der.statement_start_offset/21,(case when der.statement_end_offset-1 then DATALENGTH(der.sta…

TensorFlow学习:使用官方模型和自己的训练数据进行图片分类

前言 教程来源:清华大佬重讲机器视觉!TensorFlowOpencv:深度学习机器视觉图像处理实战教程,物体检测/缺陷检测/图像识别 注: 这个教程与官网教程有些区别,教程里的api比较旧,核心思想是没有变…

分享一下怎么做多门店商城系统

随着互联网的快速发展,传统实体店面临着巨大的挑战。为了更好地适应市场变化,提高竞争力,多门店商城系统应运而生。这种新型的商业模式,旨在通过线上线下融合,实现门店之间的互联互通,提高运营效率&#xf…

【会议征稿通知】2024第四届神经网络、信息与通信工程国际学术会议(NNICE 2024)

2024第四届神经网络、信息与通信工程国际学术会议(NNICE 2024) 2024 4th International Conference on Neural Networks, Information and Communication Engineering 2024第四神经网络、信息与通信工程国际学术会议(NNICE 2024&#xff0…

物理世界的互动之旅:Matter.js入门指南

本文简介 戴尬猴,我是德育处主任 欢迎来到《物理世界的互动之旅:Matter.js入门指南》。 本文将带您探索 Matter.js,一个强大而易于使用的 JavaScript 物理引擎库。 我将介绍 Matter.js 的基本概念,包括引擎、世界、物体和约束等…

CSS笔记-狂神

1、什么是CSS 如何学习 CSS是什么CSS怎么用(快速入门)CSS选择器(重点难点)美化网页(文字,阴影,超链接,列表,渐变…)盒子模型浮动定位网页动画(特…

【IO面试题 二】、怎么用流打开一个大文件?

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

手写效果流式响应(langchain+fastapi+js)

这是一个前后端完整可用的小项目 后端是 Python 的 FastAPI 框架,调用 langchain 进行 openai 的模型对话。前端是纯html css javascript,没调用任何第三方库,方便集成到 Vue React 等现有前端项目。 聊天界面: 效果就是提问之…

vue项目中定制化音频展示,wavesurfer.js基本使用

效果图&#xff1a; wavesurfer是一个可定制的音频波形可视化&#xff0c;建立在Audio API和HTML5 Canvas之上。 基本使用&#xff1a; <body><script src"https://unpkg.com/wavesurfer.js"></script><div id"waveform"></di…

软考系统架构师知识点集锦二:软件工程

一、考情分析 二、考点精讲 2.1 软件过程模型 &#xff08;1&#xff09;原型模型 典型的原型开发方法模型。适用于需求不明确的场景,可以帮助用户明确需求。可以分为[抛弃型原型]与[演化型原型] 原型模型两个阶段: 1、原型开发阶段;2、目标软件开发阶段。 &#x…

【深度学习】使用Pytorch实现的用于时间序列预测的各种深度学习模型类

深度学习模型类 简介按滑动时间窗口切割数据集模型类CNNGRULSTMMLPRNNTCNTransformerSeq2Seq 简介 本文所定义模型类的输入数据的形状shape统一为 [batch_size, time_step&#xff0c;n_features]&#xff0c;batch_size为批次大小&#xff0c;time_step为时间步长&#xff0c…

设计模式:桥接模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

上一篇《适配器模式》 下一篇《装饰器模式》 简介&#xff1a; 桥接模式&#xff0c;它是一种结构型设计模式&#xff0c;它的主要目的是将抽象部分与具体实现部分分离&#xff0c;使它们都可以独立地变化。…

Mingw下载---运行vscodeC++文件

下载 下载网址&#xff1a; https://sourceforge.net/projects/mingw-w64/files/mingw-w64/mingw-w64-release/ 翻到最下面&#xff0c;选择win64的安装&#xff1a; 下载完&#xff0c;解压到没有空格和中文字符的路径。不然在vscode中运行不了C代码。

软考高级之系统架构师之数据流图和流程图

数据流图 概述 数据流图&#xff0c;DFD&#xff0c;用于表示业务信息系统中的数据流&#xff0c;它表达系统中的据传从输入到存储间所涉及的程序。采用图形方式来表达系统的逻辑功能、数据在系统内部的逻辑流向和逻辑变换过程&#xff0c;是结构化系统分析方法的主要表达工具…