JVM

JVM

JVM设计的初心,是为了让java程序员感知不到系统层面的一些内容,让程序员只关注业务逻辑,不关注底层的实现细节。后来有一本书叫《深入了解java虚拟机》,这本书里面讨论了一些jvm话题,于是就掀起了jvm潮流。

1.JVM 简介

JVM 是 Java Virtual Machine 的简称,意为 Java虚拟机。
虚拟机是指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统。
常见的虚拟机:JVM、VMwave、Virtual Box。
JVM 和其他两个虚拟机的区别:

  1. VMwave与VirtualBox是通过软件模拟物理CPU的指令集,物理系统中会有很多的寄存器;
  2. JVM则是通过软件模拟Java字节码的指令集,JVM中只是主要保留了PC寄存器,其他的寄存器都进行了裁剪。
    JVM 是一台被定制过的现实当中不存在的计算机

2.JVM 运行流程

程序在执行之前先要把java代码转换成字节码(class文件),JVM 首先需要把字节码通过类加载器(ClassLoader) 把文件加载到内存中 [运行时数据区(Runtime Data Area)] ,而字节码
文件是 JVM 的一套指令集规范,并不能直接交个底层操作系统去执行,因此需要特定的命令解析器 **执行引擎(Execution Engine)**将字节码翻译成底层系统指令再交由CPU去执行,而这个过程中需要调用其他语言的接口 本地库接口(Native Interface) 来实现整个程序的功能,这就是这4个主要组成部
分的职责与功能。

3.java中的内存区域划分

jvm其实是一个java进程,java进程会从操作系统这里申请一大块内存区域,给java代码使用,这一大块内存区域,进一步划分出:
1.堆 new出来的对象和成员变量放这里
2.栈 维护方法之间的调用关系和局部变量存这里
3.方法区(旧叫法)/元数据区(新叫法) 放的是类加载之后的类对象和静态变量
这三个是最最核心的区域了
这里的面试题就是给你一段代码,问你某个变量处于内存的哪个区
判断方法是就看这个变量是局部变量还是成员变量还是静态变量
这个在哪个区跟变量的类型是没关系的,网上有的说内置类型的变量是在栈上,引用类型的变量是在堆上,这种说法是错的
在这里插入图片描述
在这里插入图片描述
堆和元数据区,在一个jvm进程中,只有一份
栈(本地方法栈和虚拟机栈)和程序计数器是存在多份的,每个线程都有一份
因为不同的线程调用的方法的顺序是不一样的,而且不同的线程下一个要执行的指令也不一样
java的线程和操作系统的线程是一对一的关系,每次在java创建出来的线程,必然会在系统中有一个对应的线程,这个线程在java的部分要有一个虚拟机栈来描述它的调用关系,在虚拟机里面,就要有一个本地方法栈来描述这个线程在被虚拟机调用之后,在虚拟机内部的本地方法调用的关系了

4.类加载

类加载简单来说就是把.class文件加载到内存,得到类对象这样的一个过程
程序员要想运行程序,就需要把程序依赖的指令和数据加载到内存中
类加载的步骤,非常复杂,但是把类加载的过程概括出了五个词,这五个词必备!!!!

1.加载阶段(Loading)

加载就是:找到.class文件,并且读文件内容
这个找.class文件,涉及到一个经典考点(双亲委派模型,下面解释)
在加载 Loading 阶段,Java虚拟机需要完成以下三件事情:
1)通过一个类的全限定名来获取定义此类的二进制字节流。
2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

2.验证阶段(Verification)

.class文件有明确的数据格式(二进制的),jvm就是要验证一下,打开读到的这个.class文件内容,是不是符合这个格式要求,要符合才能继续下一步,不符合就失败了
在这里插入图片描述

3.准备阶段(Preparation)

类加载,最终是为了得到类对象,因此准备阶段就是给类对象分配内存空间(这个空间是未初始化的内存中的数据全是0的,类对象中的静态成员啥的也是0)
相当于我租了个写字楼,但是是毛胚房,没装修

4.解析阶段(Resolution)

针对类字符串常量进行初始化
解析阶段是 Java 虚拟机将常量池内的符号引用替换为直接引用的过程,也就是初始化常量的过程
在这里插入图片描述

5.初始化阶段(Initialization)

针对类对象进行初始化(初始化静态成员,执行静态代码块,如果有父类还需要加载父类…)
初始化阶段,Java 虚拟机真正开始执行类中编写的 Java 程序代码,将主导权移交给应用程序。

类加载这个动作,不是jvm一启动,就把所有的.class文件都加载了,整体是一个“懒加载”的策略(懒汉模式),非必要,不加载
什么叫做“必要”
1.创建了这个类的实例
2.使用了这个类的静态方法/静态属性
3.使用子类,会触发父类的加载

下面我们来看一个类加载中最常见的考点

双亲委派模型

双亲委派模型出现在类加载的第一个步骤,也就是加载中的找.class文件的这个过程,它的工作就是在第一个步骤中找.class文件这个过程
这个双亲委派模型,并非是类加载中的一个很重要的步骤,但是确实是考察频率最高的东西,俺猜是因为名字好听
首先我们要知道
JVM中,加载类,需要用到一组特殊的模块,类加载器
在JVM中,内置了三个类加载器
BootStrap ClassLoader 负责加载 Java标准库中的类
Extension ClassLoader 负责加载一些非标准的但是Sun/Oracle扩展的库的类
Application ClassLoader 负责加载项目中自己写的类 以及 第三方库 中的类

Extension 是Application 的爹,BootStrap 是Extension 的爹
在这里插入图片描述
这个就是双亲委派模式,看图只有父亲,没有母亲,为啥叫双亲呢?
是翻译问题,双亲好听!
双亲委派模型可以被打破的,如果你自己实现了一个,你可以遵守双亲委派模型,也可以不遵守

5.JVM垃圾回收(GC)

帮助程序员自动释放内存空间的

C语言中,malloc的内存必须手动free,否则就容易出现内存泄露(光申请内存,不施放,内存逐渐用完了,导致程序崩溃),于是java等后续编程语言引入了GC来解决上述问题,能够有效的减少内存泄露的出现概率

其实内存释放时一种很纠结的事情
申请的时机是明确的=>使用到了必须要申请
释放的时机是模糊的=>彻底不使用了才能释放
C/C++做法是完全让程序猿来决定,比较不靠谱的,特别依赖程序猿的水平
Java通过JVM自动判定基于一系列策略就可以让这个准确性比较高,但是也会付出一些代价

JVM中的内存分为好几个区域,GC主要释放的是哪个空间呢?
堆!!!(new出来的对象)
程序计数器,就是一个单纯存地址的整数,不需要随着线程一起销毁.
栈,也是随着线程一起销毁.方法调用完毕,方法的局部变量自然随着出栈操作就销毁了
元数据区/方法区,存的类对象,很少会“卸载”

GC说是释放内存,其实是释放对象,GC是以对象为单位进行释放的
GC主要分为两个阶段
1.找到谁是垃圾
2.把垃圾对象的内存给释放掉
针对这两个阶段,有了一些垃圾回收算法
这里提到的垃圾回收算法,是基本的思想,不代表jvm真实的实现方式,jvm的真实实现方式是基于这些思想方法,但是又做出了很多细节上的调整和优化,我们只需要掌握最基本的思想就足以应付面试了
先说第一步

1.找,确认垃圾( 死亡对象的判断的算法)

一个对象,如果后续再也不用了,就可以认为是垃圾
Java中使用一个对象,只能通过引用!!如果一个对象,没有引用指向他,此时这个对象一定是无法被使用的(妥妥的是垃圾),就释放,如果一个对象已经不想用了,但是这个引用可能还指向着呢,就不释放,Java中只是单纯通过引用没有指向这个操作,来判定垃圾的
Java对于垃圾对象的识别是比较保守的,最大程度的避免“误杀”,释放不及时,是小事。误杀是大事
那么具体来说,怎样知道一个java对象是否有引用指向呢?

引用计数算法

给对象里安排一个额外的空间,这个空间保存一个整数,表示该对象有几个引用指向(实际java没有用这个算法,但是py,php采取了,也是一种典型的算法)
在这里插入图片描述
两个缺陷:
1.浪费内存空间(假如我这个对象很小,只有5个字节,但是我还要空出来4个字节来计数)
2.存在循环引用的情况,会导致引用计数的判定逻辑出错
在这里插入图片描述
在这里插入图片描述

可达性分析算法

(这个是java采取的)把对象之间的引用关系,理解成了一个树形结构.从一些特殊的起点出发,进行遍历.只要能遍历访问到的对象,就是“可达”.再把“不可达的”当做垃圾即可
在这里插入图片描述
可达性分析,克服了引用计数的两个缺点,但是也有自己的问题
1.消耗更多的时间,因此某个对象成了垃圾,也不一定能第一时间发现,因为扫描的过程,需要消耗时间
2.在进行可达性分析的时候,要顺腾摸瓜,一旦这个过程中,当前代码的对象的引用关系发生变化了,就还麻烦了,因此,为了更准确的完成这个摸瓜的过程,需要让其他的业务线程暂停工作(STW问题—stop the world)
(java这里发展这么多年,垃圾回收这里也在不断优化,STW这个问题,现在已经能够比较好的应付了,不能完全消除,但是已经可以让STW的时间尽可能的短了)

2.把垃圾对象的内存给释放掉(垃圾回收算法)

标记清除算法

直接把内存中的垃圾对象释放
在这里插入图片描述
虽然说简单,但是太粗暴了,因此为了避免内存碎片,又引入了复制算法

复制算法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
万一你要的内存空间一开始就大于这个申请内存的一半,复制算法就用不了了
复制算法,解决了内存碎片问题,但是也有缺点
1.内存利用率比较低
2.如果当前的对象大部分都是要保留的,垃圾很少,此时复制成本就比较高了
用复制算法的合适场景是垃圾占大多数
针对复制算法也有部分局限性,于是就引入了第三种算法

标记整理算法

在这里插入图片描述
解决了内存碎片问题,但是搬运开销也比较大

这么一看上述三种的方法好像都不咋地
因此JVM实际上的实现思路,是结合了上述几种思想方法,又搞出来了一个分代回收思想

分代回收算法

针对不同的情况使用不同的策略,取长补短
给对象设定了“年龄”这样的概念,描述了这个对象存在多久了.如果一个对象刚诞生,认为是0岁.每次经过一轮扫描(可达性分析),没被标记成垃圾,这个时候对象就涨一岁,通过年龄来区分这个对象的存活时间
经验规律:如果一个对象存活时间很长了,他将继续存在更长的时间(要死早死了)
在这里插入图片描述

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

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

相关文章

Python语法之条件语句(很详细)

目录 Python条件语句的介绍 定义 if的语法和实例(最基本的) 语法 gif动态图展示 具体实例 实现思路: if-elif-else的语法和实例(最基本的) 语法 具体实例 实现思路: 判断需要多个条件需同时判断语法和实例(最基…

华为云云耀云服务器L实例评测 | 云服务器搭建自己的gitlab代码仓库手把手教学

📋 前言 🖱 博客主页:在下马农的碎碎念🤗 欢迎关注🔎点赞👍收藏⭐️留言📝✍ 本文由在下马农原创,首发于CSDN📆 首发时间:2023/09/26📅 最近更新时…

【STM32单片机】u8g2智能风扇设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用STM32F103C8T6单片机控制器,使用按键、IIC OLED模块、DS18B20温度传感器、直流电机、红外遥控等。 主要功能: 初始化后进入温度显示界面,系统初始状态为手动…

医院陪诊小程序源码 陪诊陪护小程序源码

医院陪诊小程序源码 陪诊陪护小程序源码 近年来,随着互联网技术的不断发展,我们的生活中出现了越来越多的智能设备和智能应用,这些智能应用不仅极大方便了我们的生活,还对现代医疗服务体验产生了深远的影响。本文将为大家介绍一种…

JVM G1垃圾回收器学习笔记

前言 最近在工作中遇到频繁FullGC且YoungGC时间有时特别长的情况,而自己对JVM的垃圾回收也是一知半解,因此需要对JVM做系统的了解,为快速解决工作中的问题,能有效分析GC日志和业务代码,先从G1垃圾回收器开始学习&…

贪心算法-

代码随想录 什么是贪心 贪心的本质是选择每一阶段的局部最优,从而达到全局最优。 这么说有点抽象,来举一个例子: 例如,有一堆钞票,你可以拿走十张,如果想达到最大的金额,你要怎么拿&#xff…

linux驱动之input子系统简述

文章目录 一、什么是input子系统二、内核代码三、代码分析 一、什么是input子系统 Input驱动程序是linux输入设备的驱动程序,我们最常见的就按键,触摸,插拔耳机这些。其中事件设备驱动程序是目前通用的驱动程序,可支持键盘、鼠标…

邮件营销方案

互联网的快速发展,使得新媒体营销、短视频营销、微信营销等新型营销方式成为主流。但是邮件营销仍然是性价比很高的营销方式之一,它不仅可以帮助你与潜在客户建立联系、传达信息并促进销售,同时也是维系老客户的重要手段之一。特别是对于外贸…

解答嵌入式和单片机的关系

嵌入式系统是一种特殊的计算机系统,用于特定任务或功能。而单片机则是嵌入式系统的核心部件之一,是一种在单个芯片上集成了处理器、内存、输入输出接口等功能的微控制器。刚刚好我这里有一套单片机保姆式教学,里面有编程教学、问题讲解、语言…

C++:优先级队列模拟实现和仿函数的概念使用

文章目录 使用方法Compare仿函数一些场景模板参数和函数参数 本篇总结优先级队列 使用方法 首先在官网查看它的一些用法 template <class T, class Container vector<T>,class Compare less<typename Container::value_type> > class priority_queue;从…

【golang】深入理解Go语言垃圾回收(GC)

垃圾回收 垃圾回收版本1.3之前标记-清除&#xff08;mark and sweep&#xff09;算法标记-清除&#xff08;mark and sweep&#xff09;的缺点 版本1.5的三色并发标记法没有STW的三色标记法屏障机制强-弱 三色不等式插入屏障删除屏障 版本1.8的混合写屏障&#xff08;hybrid wr…

【计算机网络】——数据链路层(应用:局域网、广域网、设备 )

//仅做个人复习和技术交流&#xff0c;图片取自王道考研&#xff0c;侵删 一、大纲 1、介质访问控制 信道划分介质访问控制 随机访问介质访问控制 2、局域网 3、广域网 4、数据链路层设备 二、局域网 1、局域网基本概念和体系结构 局域网(LocalArea Network): 简称LAN&…

[maven] 实现使用 plugin 及 properties 简述

[maven] 实现&使用 plugin 及 properties 简述 这章内容&#xff0c;我个人感觉可看可不看……&#xff1f; 不过课都上了&#xff0c;笔记 &#x1f4d2; 补完才对得起自己嘛 plugins 主要讲一下 maven 的 plugin 时怎么实现的&#xff0c;以及项目中怎么调用自己实现…

实现电商跨平台订单每日自动对账

场景描述&#xff1a; 多数商家都存在多电商平台同时经营的情况&#xff0c;而进行订单对账则是相关业务或财务人员的每日必修课。比如商家在天猫&#xff0c;苏宁&#xff0c;1号店&#xff0c;京东等均有运营店铺&#xff0c;每天需要通过各电商后台系统抓单打单&#xff0c…

若依cloud -【 100 ~ 103 】

100 分布式日志介绍 | RuoYi 分布式日志就相当于把日志存储在不同的设备上面。比如若依项目中有ruoyi-modules-file、ruoyi-modules-gen、ruoyi-modules-job、ruoyi-modules-system四个应用&#xff0c;每个应用都部署在单独的一台机器里边&#xff0c;应用对应的日志的也单独存…

springboot如何接入netty,实现在线统计人数?

springboot如何接入netty&#xff0c;实现在线统计人数&#xff1f; Netty 是 一个异步事件驱动的网络应用程序框架 &#xff0c;用于快速开发可维护的高性能协议服务器和客户端。 Netty ​ 是一个 NIO 客户端服务器框架 ​&#xff0c;可以快速轻松地开发协议服务器和客户端等…

微表情识别API + c++并发服务器系统

微表情识别API c并发服务器系统 该项目只开源c并发服务器程序&#xff0c;模型API部分不开源 地址&#xff1a;https://github.com/lin-lai/-API- 更新功能 4.1版本 改用epoll实现IO多路复用并发服务器 项目介绍 本项目用于检测并识别视频中人脸的微表情 目标任务: 用户上…

【李沐深度学习笔记】线性代数

课程地址和说明 线性代数p1 本系列文章是我学习李沐老师深度学习系列课程的学习笔记&#xff0c;可能会对李沐老师上课没讲到的进行补充。 线性代数 标量 标量&#xff08;scalar&#xff09;&#xff0c;亦称“无向量”。有些物理量&#xff0c;只具有数值大小&#xff0c…

基于微信小程序的校园失物招领系统设计与实现(源码+lw+部署文档+讲解等)

前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb;…

Qt创建线程(使用moveToThread方法创建子线程)

1.moveTothread方法: &#xff08;1&#xff09;要使用moveToThread方法必须继承与QObject类 &#xff08;2&#xff09;创建任务对象时不能指定父对象 例子&#xff1a; MyWork* work new MyWork(this); // error MyWork* work new MyWork; // ok &#xff08;3&#…