【JVM】Java虚拟机

本文主要介绍了JVM的内存区域划分,类加载机制以及垃圾回收机制.

其实JVM的初心,就是让java程序员不需要去了解JVM的细节,它把很多工作内部封装好了.但是学习JVM的内部原理有利于我们深入理解学习Java. 

1.JVM的内存区域划分

JVM其实是一个java进程 ; 每个java进程,就是一个jvm的实例

JVM的内存区域划分

放new的对象

方法区(元数据区)

放类对象,类(.class文件),方法内容,static成员

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

注意:

栈空间和程序计数器,是每个线程有一份.(每个线程都有一个独立的执行逻辑)

面试题:给一段代码,问某个变量在哪个内存区域中

2.JVM类加载机制

类加载:Java程序最开始写的是一个.java文件,编程成.class文件.运行java程序的时候,JVM会读取.class文件,把文件的内容放到内存中,并且构造成.class对象(类对象)   . 也就是把类从硬盘文件中,加载到内存中.

类加载的大致过程

1.加载

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

2.验证

检查当前的.class文件的格式是否符合要求.

3.准备

给类对象分配内存

最终的目的是构造出完成的类对象,分配存在+初始化

4.解析

主要是初始化类对象中涉及到的一些字符串常量

字符串常量在.class文件本身就已经存在,直接读到内存中.

此处是将字符串的符合引用(偏移位置)替换为直接引用/真实的内存地址的过程

5.初始化

对类对象进行更具体地初始化操作,初始化静态成员,执行静态代码块,加载父类.

双亲委派模型

描述了类加载过程中,如何找.class文件

JVM中加载.class文件,需要用到类加载器模块 . JVM中自带了三个类加载器 .

Bootstrap ClassLoader

负责加载标准库的类. Java有一个标准文档,描述了都要提供的类

Extension ClassLoader

负责加载JVM扩展的库.   除了标准库之外,实现JVM的厂商,还会再添加一些类

Application ClassLoader

负责加载第三方库.  比如mysql jdbc driver / servlet / jackson

关系

第一个是第二个的父亲

第二个是第三个的父亲

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

流程:

1.从Application ClassLoader开始

不会立即搜索第三方库的目录,而是先把加载任务委派给父亲,让父亲尝试加载

2.到了Extension ClassLoader

也不会立即就搜索到扩展库的目录,也是把加载任务委派给父亲.也让父亲先尝试加载

3.到了Bootstrap ClassLoader

也不会立即标准库,而是也想把任务委派给父亲,但是bootstrap ClassLoader没有父亲,就只能自己动手搜索类了.

目的:明确优先级.

标准库的类最优先加载 - >扩展库其次 -> 第三方库最低.

比如:

标准库中有一个java.lang.String , 自己写的代码中也有一个java.lang.String

JVM始终都是先加载标准库,而不会加载自己写的类, 避免程序员的代码,对标准库的代码产生负面影响.


一个类,什么时候会被加载

懒汉模式  ---- 用到才加载.

1.构造类的实例

2.使用了类的静态方法/静态属性

3.子类的加载会触发父类

类加载之后,后续使用就不必加载了.


类卸载

把对象干掉

一般情况下,不会考虑卸载,一直会保持到程序运行结束

热补丁(重启服务器)

有时候代码有bug,正常操作是修改代码,重新编译,新版本替带旧版本,重启服务器

冷不丁(不用重启服务器)

有些情况,不方便重启,就可以打补丁,通过一些方法把旧版本的类给卸载掉,直接用加载好的新的类替换,不重启服务器,也可以更新代码 .

3.垃圾回收 GC

C语言通过malloc申请的内存需要程序员手动释放,这当然是非常不靠谱的做法.而Java引入垃圾回收机制,可以自动的判定某个内存是否会继续使用;如果不会,就会把这个内存当成垃圾,自己把垃圾释放掉.再Java的影响下,后续的python/Go/PHP/Ruby大部分语言都采取了垃圾回收方式来释放内存.

而c++由于希望和C兼容还有对性能的追求,并没有引入垃圾回收机制.

引入GC机制就会引入额外的系统开销,并且还会可能影响程序效率.

可幸的是,Java中的GC已经优化多年,对于效率的影响已经越来越小了.


回收什么?

对于Java 来说,垃圾回收,回收的其实是对象,而不是字节

JVM中有好几个内存区域,GC回收的是哪里的对象

  • 占空间不需要GC对象,栈里面包含很多栈帧,每个栈帧对应一个方法,该方法执行结束,此时这个栈帧就销毁了,栈帧上的局部变量自然销毁
  • 每个栈帧都有的程序计数器/线程销毁,自然也销毁.
  • 方法区:类对象很少会涉及到对象的卸载
  • 堆:GC的主战场.

步骤

垃圾回收分两步:

1.判定对象是否是垃圾

垃圾:如果一个对象在后续代码中,不会被继续使用到了; Java中如果没有任何引用指向它,那它就是垃圾了 .

(在Java中,使用一个对象的唯一途径是:声明一个引用指向它,然后再通过引用访问对象)

引用计数

思路1:引用计数(Python/PHP的虚拟机的GC使用的是该方法)

给对象内部安排一个计数器,每次有引用指向它,计数器+1;每次引用被销毁,计数器-1 ;

当计数器为0,意味着对象就是垃圾.

这种方案的缺陷:

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

每个对象都要一块空间来存储引用计数.

2.可能存在循环引用的问题. 导致对象不能被正确地识别.

可达性分析

思路2(Java使用)

JVM首先会从现有代码中的能直接访问到的引用(栈上的局部变量/常量池里的引用/方法区里的静态成员)出发,尝试遍历所有能访问到的对象.

只要对象能访问到,就会标记成"可达",完成整个遍历之后,可达之外的对象,也就是"不可达",

也就相当于是垃圾了.

gc roots进行这样的扫描 :

这个遍历的过程就是可达性分析.

和引用计数不同,引用计数消耗的是空间;而可达性分析,消耗的是时间,并不会引入额外的空间开销,但是进行上述的遍历,需要消耗时间.

 由于一个对象是否是垃圾,往往是动态变化的.因此可达性分析是周期性的

2.释放对象

如何清理垃圾/释放对象

1.标记清楚 (直接释放)

直接释放对象,就会引起内存碎片

由于申请内存的时候,都是连续的的内存空间;如果释放,就可能会破坏原有的连续性,导致有内存,但是申请不了.

内存碎片随着程序的运行越来越多,越来越碎,内存就更难申请了.

2.复制算法

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

把一个内存分成两份,用一份,丢一份;

把左侧区域中有效的对象复制到右侧,接下来就可以使用右侧区域;

等右侧产生的很多碎片,再将对象复制到左侧,右边空间统一释放 ; 来回利用

缺陷:如果复制的内容很多,开销大;空间利用率也不高.

3.标记整理

类似于顺序表删除元素,搬运元素

缺陷:搬运成本高.

上述三种方法都有各自的缺陷

JVM采取的方法是在不同的场景下,使用不同的回收方式.

对象可以分为两类,一类是生命周期比较长的,一类是生命周期比较短的 ; 生命短的经历gc扫描的次数就少 ,生命长的经历gc扫描的次数就多 .  我们就可以将这两种对象放在不同的区域内,根据他们的特点使用不用的方法解决内存碎片问题 .

  • 新生代 : 每一轮gc留下的对象比较少, 复制开销不大, 以复制算法为主
  • 老年代 : 出现回收的概率比较低,此时搬运的开销不大. 以标记整理为主
  • 特殊情况: 如果对象体积特别大,就会直接进入老年带(大对象不适合进行复制算法)

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

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

相关文章

Apache Airflow (九) :Airflow Operators及案例之BashOperator及调度Shell命令及脚本

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹…

科技创新 共铸典范 | 江西卫健办邓敏、飞图影像董事长洪诗诗一行到访拓世科技集团,提振公共卫生事业发展

2023年11月15日,拓世科技集团总部迎来了江西省卫健项目办项目负责人邓敏、江西飞图影像科技有限公司董事长洪诗诗一行的考察参观,集团董事长李火亮、集团高级副总裁方高强进行热情接待。此次多方交流,旨在共同探讨携手合作,激发科…

Django+Vue项目创建 跑通

参考链接: 【精选】DjangoVue项目构建_django vue-CSDN博客 一、背景 主要介绍如何使用后端Django 前端Vue 的技术栈快速地搭建起一套web项目的框架。 为什么使用Django和Vue? Django是Python体系下最成熟的web框架之一,由于Python语言的易用…

【机器学习Python实战】线性回归

🚀个人主页:为梦而生~ 关注我一起学习吧! 💡专栏:机器学习python实战 欢迎订阅!后面的内容会越来越有意思~ ⭐内容说明:本专栏主要针对机器学习专栏的基础内容进行python的实现,部分…

Redux-状态管理组件

一、简介 react中的状态只属于某个组件。而Redux是一个全局管理js状态的架构,让组件通信更加容易。 之前是状态在所有组件间传递,而redux通过store来实现这个功能。 Redux特性: 1.Single source Of truth,通过store唯一维护状态…

网工内推 | 国企、港企网工,年底双薪,NA以上认证即可

01 中航期货有限公司 招聘岗位:信息技术部-网络工程师 职责描述: 1、负责总部、分支机构、外联单位网络的日常运维、故障和应急处置,特别是定期监测设备的运行状态,对存在隐患的地方及时发现改正,保持网络稳定通畅&am…

Java 12 及Tomcat 部署配置

使用的软件版本 1. Java12部署 和之前的Java版本不太一样,12版本不用配置JRE环境。 解压缩文件夹 root账户执行 tar -xzvf /home/software/jdk-12.0.2_linux-x64_bin.tar.gz创建java文件夹 root账户执行 cd /usr mkdir java移动Java文件到创建的文件夹下 root账…

多态语法详解

多态语法详解 一:概念1:多态实现条件 二:重写:三:向上转型和向下转型1:向上转型:1:直接赋值:2:方法传参3:返回值 2:向下转型 一:概念 1:同一个引…

LINMP搭建wordpress-数据库不分离

目录 一、nginx部署 1.安装nginx前的系统依赖环境检查 2.下载nginx源代码包 3.解压缩源码包 4.创建普通的nginx用户 5.开始编译安装nginx服务 6.创建一个软连接以供集中管理 7.配置nginx环境变量 二、mysql 1.创建普通mysql用户 2.下载mysql二进制代码包 3.创建mys…

力扣刷题-二叉树-完全二叉树的节点个数

222.完全二叉树的节点个数 给出一个完全二叉树,求出该树的节点个数。 示例 1: 输入:root [1,2,3,4,5,6] 输出:6 示例 2: 输入:root [] 输出:0 示例 3: 输入:root [1]…

鸿蒙4.0开发笔记之DevEco Studio之配置代码片段快速生成(三)

一、作用 配置代码片段可以让我们在Deveco Studio中进行开发时快速调取常用的代码块、字符串或者某段具有特殊含义的文字。其实现方式类似于调用定义好变量,然而这个变量是存在于Deveco Studio中的,并不会占用项目的资源。 二、配置代码段的方法 1、打…

微信小程序配置企业微信的在线客服

配置企业微信后台 代码实现 <button tap"openCustomerServiceChat">打开企业微信客服</button>methods: {openCustomerServiceChat(){wx.openCustomerServiceChat({extInfo: {url: 你刚才的客服地址},corpId: 企业微信的id,showMessageCard: true,});} …

力扣刷题-二叉树-二叉树最小深度

给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明&#xff1a;叶子节点是指没有子节点的节点。&#xff08;注意题意&#xff09; 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#x…

【数据结构】图的简介(图的逻辑结构)

一.引例&#xff08;哥尼斯堡七桥问题&#xff09; 哥尼斯堡七桥问题是指在哥尼斯堡市&#xff08;今属俄罗斯&#xff09;的普雷格尔河&#xff08;Pregel River&#xff09;中&#xff0c;是否可以走遍每座桥一次且仅一次&#xff0c;最后回到起点的问题。这个问题被认为是图…

给大伙讲个笑话:阿里云服务器开了安全组防火墙还是无法访问到服务

铺垫&#xff1a; 某天我在阿里云上买了一个服务器&#xff0c;买完我就通过MobaXterm进行了ssh&#xff08;这个软件是会保存登录信息的&#xff09; 故事开始&#xff1a; 过了n天之后我想用这个服务器来部署流媒体服务&#xff0c;咔咔两下就部署好了流媒体服务器&#x…

7年经验之谈 —— 如何高效的开展app的性能测试?

APP性能测试是什么 从网上查了一下&#xff0c;貌似也没什么特别的定义&#xff0c;我这边根据自己的经验给出一个自己的定义&#xff0c;如有巧合纯属雷同。 客户端性能测试就是&#xff0c;从业务和用户的角度出发&#xff0c;设计合理且有效的性能测试场景&#xff0c;制定…

pytorch的backward()的底层实现逻辑

自动微分是一种计算张量&#xff08;tensors&#xff09;的梯度&#xff08;gradients&#xff09;的技术&#xff0c;它在深度学习中非常有用。自动微分的基本思想是&#xff1a; 自动微分会记录数据&#xff08;张量&#xff09;和所有执行的操作&#xff08;以及产生的新张…

什么是Mock?为什么要使用Mock呢?

1、前言 在日常开发过程中&#xff0c;大家经常都会遇到&#xff1a;新需求来了&#xff0c;但是需要跟第三方接口来对接&#xff0c;第三方服务还没好&#xff0c;我们自己的功能设计如何继续呢&#xff1f;这里&#xff0c;给大家推荐一下Mock方案。 2、场景示例 2.1、场景一…

HTTP四种请求方式,状态码,请求和响应报文

1.get请求 一般用于获取数据请求参数在URL后面请求参数的大小有限制 2.post请求 一般用于修改数据提交的数据在请求体中提交数据的大小没有限制 3.put请求 一般用于添加数据 4.delete请求 一般用于删除数据 5.一次完整的http请求过程 域名解析&#xff1a;使用DNS协议…