JavaEE-JVM的学习

news2024/11/18 5:44:30

目录

  • JVM执行流程
  • JVM内存区域划分
    • 程序计时器
    • 方法区
  • JVM类加载机制
    • 1)Loading环节
    • 2)Linking环节
      • 2.1) Verification
      • 2.2)Preparation
      • 2.3)Resolution
    • 3)Initializing
  • JVM典型面试题
  • JVM的垃圾回收机制(GC)
    • 分代回收

JVM执行流程

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

在这里插入图片描述

总结来看, JVM 主要通过分为以下 4 个部分,来执行 Java 程序的,它们分别是:

  1. 类加载器(ClassLoader)
  2. 运行时数据区(Runtime Data Area)
  3. 执行引擎(Execution Engine)
  4. 本地库接口(Native Interface)

JVM内存区域划分

程序计时器

内存中最小的区域。
保存了下一条要执行的指令的地址在哪~

指令=>字节码
程序要想运行,JVM就得把字节码加载起来,放到内存中~
程序就会一条一条把指令从内存取出来,放到CPU上执行
也就需要随时记住,当前执行到哪一条了~~

CPU是并发式执行程序的~CPU不是只给你一个进程提供服务的,要服务所有的进程

正因为操作系统是以线程位单位进行调度执行的,每个线程都得记录自己的执行位置。
程序计数器,会每个线程都有一个~

局部变量和方法调用信息

方法调用的时候,每次都调用一个新的方法,都涉及到“入栈”操作。
每次执行完一个方法,都涉及到“出栈”操作~

在这里插入图片描述
每个线程有一份。

一个进程只有一份,多个线程公用一个堆~
也是内存中空间最大的区域~

new出来的对象,就是在堆中,对象的成员变量也在堆中。

内置类型的变量,在栈上。
引用类型的变量,在堆上。
这个说法正确吗?
不正确,局部变量,在栈上。成员变量和new的对象,在堆上。

方法区

方法区中,放的是“类对象”。
.java -> .class(二进制字节码)
.class会被加载到内存中,也就被JVM构造成了类对象(加载的过程就成为“类加载”)
这里的类对象,就是放到方法区中,类对象就描述这个类长啥样~
在这里插入图片描述
static 修饰的成员,就成为了"类属性"
而普通成员,叫做“实例属性”.

JVM类加载机制

类加载,其实是设计一个运行时环境的一个重要的核心的功能.

类加载是要干啥?
把.class文件加载到内存中,构建成类对象。

在这里插入图片描述

1)Loading环节

先找到对应的.class文件,然后打开并读取.class文件,同时初步生成一个类对象
Loading中的一个关键环节,.class里面到底是什么样的?

在这里插入图片描述
实现编译器,要按照这个格式来构造
实现JVM要按照这个格式来加载
观察这个格式,就可以看到.class文件就把.java文件中的核心信息都表达进去了~

u4就是4个字节的unsigned int
u2就是2个字节的unsigned int
cp_info/field_info都是结构体

magic 标识文件的格式

会把读取和解析到的信息,初步填写到类对象中

2)Linking环节

连接一般就是建立号多个实体之间的联系~

2.1) Verification

主要就是验证读到的内容是不是和规范中规定的格式完全匹配~
如果发现这里读到的数据格式不符合规范,就会类加载失败,并且抛出异常~

2.2)Preparation

准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值的阶段。
给静态变量分配内存,并且设置0值。

2.3)Resolution

解析阶段是 Java 虚拟机将常量池内的符号引用替换为直接引用的过程,也就是初始化常量的过程。
.class文件中,常量时集中放置的,每个常量有一个编号,.class文件的结构体初始情况下只是记录了编号,就需要根据编号找到对应的内容,填充到类对象中

3)Initializing

真正对类对象进行初始化,尤其时针对静态成员.

JVM典型面试题

1.问下面的代码的执行结果是什么?

class A {
    public A() {
        System.out.println("A 的构造方法");
    }

    {
        System.out.println("A 的构造代码块");
    }

    static {
        System.out.println("A 的静态代码块");
    }
}

class B extends A {
    public B() {
        System.out.println("B 的构造方法");
    }

    {
        System.out.println("B 的构造代码块");
    }

    static {
        System.out.println("B 的静态代码块");
    }
}

public class Test extends B {
    public static void main(String[] args) {
        new Test();
        new Test();
    }
}

答案如下:
在这里插入图片描述

原理:
类加载阶段会进行静态代码块的执行,要想创建实例,要先进行类加载。
静态代码块只是类加载阶段执行一次。
构造方法和构造代码块,每次实例化都会执行,构造代码块在构造方法前面~~
父类执行在前,子类执行在后~

2.“双亲委派模型”
这个东西时类加载的一个环节
这个环节处于Loading阶段的。
双亲委派模型,描述的就是JVM中的类加载器,如何根据类的全限定名找到.class文件的过程.

JVM里提供了专门的对象,叫做类加载器,负责进行类加载.
当然找文件的过程也是类加载器来负责的~

.class文件,可能放置的位置有很多,有的要放到JDK目录里,有的放到项目目录里,还有在其他特定位置…
因此,JVM里面提供了多个类加载器,每个类加载器负责一个片区~~
默认的类加载器,主要是3个~
1.BootStrapClassLoader 负责加载标准库中的类
2.ExtensionClassLoader 负责加载JDK扩展的类
3.ApplicationClassLoader 负责加载当前项目目录中的类~

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

JVM的垃圾回收机制(GC)

在这里插入图片描述
垃圾回收的劣势:
1.消耗额外的开销~(消耗资源更多了)
2.可能会影响程序的流畅运行~(垃圾回收经常会引入STW问题(Stop The World))

垃圾回收要回收啥?
内存,有很多种~
1.程序计数器 -> 固定大小,不涉及刀释放,就不需要GC
2.栈 ->函数执行完毕,对应的栈帧就自动释放了,也不需要GC
3.堆 ->最需要GC的,代码中大量的内存都在堆上
4.方法区 ->类对象,类加载来的,进行“类卸载”就需要释放内存,卸载操作是一个非常低频的操作~

在这里插入图片描述
如何组织里,人都有三个派别:
1.积极派
2.消极派
3.中间摇摆派

上述三个派别,哪些是要进行回收释放内存的?
对于中间摇摆派,一部分仍在使用,一部分不再使用的对象,整体来说是不释放的
GC中就不会出现,“半个对象”的情况~

垃圾回收的基本单位,是“对象”,而不是“字节”

GC,会提高开发效率,降低程序自身的运行效率。

垃圾回收,具体是如何回收的~

第一阶段:找垃圾/判定垃圾
第二阶段:释放垃圾

如何找垃圾/判定垃圾

主流的思路,有两种方案
1.基于引用计数(不是Java采取的方案)

针对每个对象,都会额外引入一小块内存,保存这个对象有多少个引用指向它
在这里插入图片描述

class Test {
	Test t = null;
}
Test t1 = new Test();
Test t2 = new Test();

在这里插入图片描述

t1.t = t2;

在这里插入图片描述

t2.t = t1;

在这里插入图片描述

t1 = null;
t2 = null;

在这里插入图片描述
此时此刻,两个对象的引用计数,不为0,所以无法释放,但是由于引用长在彼此的身上,外界的代码无法访问到这两个对象~
此时此刻,这两对象就被孤立了,既不能使用,又不难释放~这就出现了“内存泄露”的问题。

2.基于可达性分析(这是Java采取的方案)
通过额外的线程,定期的针对整个内存空间的对象进行扫描~
有一些起始位置(称为GCRoots),会类似于深度优先遍历一样,把可以访问到的对象都标记一遍(带标记的对象就是可达的对象),没被标记的对象,就是不可达的,也就是垃圾~
在这里插入图片描述
回收垃圾

三种基本策略:
1.标记-清除

在这里插入图片描述
如果直接释放,虽然内存是还给系统了,但是被释放的内存是离散的(不是连续的)
分散开,带来的问题就是“内存碎片”
空闲的内存,有很多,假设一共是1G
如果要申请500M内存,也是可能申请失败的(因为要申请的500M是连续内存)每次申请,都是申请的连续的内存空间,而这里的1G可能是多个碎片加在一起,才是1G。

2.复制算法
为了解决内存碎片,引入的复制算法
在这里插入图片描述

用一半,丢一半
直接把不是垃圾的,拷贝到另一半,把原来整个空间整体都释放掉!

复制算法的问题:
1.内存空间利用率低
2.如果保留的对象多,要释放的对象少,此时复制开销大

3.标记-整理
在这里插入图片描述

分代回收

实际的JVM中的实现,会把很多方案结合起来使用
分代回收,针对对象进行分类(根据对象的“年龄”分类)

在这里插入图片描述

1.刚创建出来的对象,就放在伊甸区
2.如果伊甸区的对象熬过一轮GC扫描,就会被拷贝到幸存区
3.在后续的几轮GC中,幸存区的对象,就在两个幸存区里面来回拷贝
4.在持续若干轮之后,对象进入老年代

分代回收中,还有一个特殊情况,有一类对象可以直接进入老年代~(大对象,占有内存多的对象)
大对象拷贝开销比较大, 不适合复制算法~

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

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

相关文章

盘点一个Python自动化办公需求,实现数据自动填充(下篇)

点击上方“Python爬虫与数据挖掘”,进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 七月七日长生殿,夜半无人私语时。 大家好,我是皮皮。 一、前言 前几天遇到了一个小需求,粉丝自己在实际工作中的需求…

回顾 | Semantic Kernel:面向 AI 编程(二) - Prompt Skill

点击蓝字 关注我们 编辑:Alan Wang 排版:Rani Sun 微软 Reactor 为帮助广开发者,技术爱好者,更好的学习 .NET Core, C#, Python,数据科学,机器学习,AI,区块链, IoT 等技术&#xff0…

子集II--(回溯+去重)

1题目 给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。 解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。 示例 1: 输入:nums [1,2…

基于最大似然反射率的异构激光雷达强度标定方案(开源)

文章:Maximum Likelihood Remission Calibration for Groups of Heterogeneous Laser Scanners 作者:Bastian Steder Michael Ruhnke Rainer Kummerle Wolfram Burgard 编辑:点云PCL 代码:https://github.com/soytony/IntensityCa…

vue 更新数组的方法

在 vue中,我们可以通过给数组添加索引来更新数组的值,比如我们需要在一个新的页面中添加一个新的元素,那么我们就可以通过给这个数组添加索引来实现。那么有朋友就会问了,为什么不直接在 vue中直接添加一个新的元素呢?…

chatgpt赋能python:Python列表排列顺序详解

Python列表排列顺序详解 作为一门功能丰富的高级编程语言,Python在不同类型的开发任务中广泛应用。其中,列表是一种常见的数据类型,用于存储多个元素。Python列表可以包含任何类型的数据,包括数字、字符串和其他列表等&#xff0…

干洗店软件,洗衣洗鞋线上下单小程序开发

干洗店软件洗衣洗鞋线上下单小程序; 可以实现客户自助办理,也可以和公众号、小程序等结合起来。干洗店软件可以实现客户管理,如积分管理,产品设置等功能。 线上下单,上门取货,订单拍照,订阅提示…

开发者实战 | 分割一切?Segment Anything 量化加速实战

点击蓝字 关注我们,让开发变得更有趣 作者 | 杨亦诚 排版 | 李擎 分割一切? Segment Anything 量化加速实战 前言 “分割一切,大家一起失业!”——近期,这样一句话在社交媒体上大火!这讲的就是 Segment Anything Model&#xff08…

chatgpt赋能python:Python创建一个Person类

Python 创建一个 Person 类 Python 是一种高级编程语言,因为它易于学习和使用,并且可以用于多种用途。使用 Python,您可以轻松创建各种程序,从简单的脚本到完整的应用程序。Python 的一个重要特点是它的面向对象编程能力&#xf…

「VS」Visual Studio 字符集

✨博客主页:何曾参静谧的博客 📌文章专栏:「VS」Visual Studio 当我们在使用 Visual Studio 编写程序时,经常会遇到字符集的问题。在 Visual Studio 中,字符集选项有两个选项:Unicode 字符集和多字节字符集…

期刊和会议如何查询、期刊级别分类和顶会概念一文精析

期刊和会议查询、期刊级别分类和顶会概念分析 一、如何查询期刊和会议1.中文期刊-用知网出版物检索2.外文期刊-一般用letpub3.会议查询 二、国内期刊的正刊三、国内核心期刊四、国际核心期刊五、ESCI、SCI和SCIE的区别六、国际会议核心七、普刊八、顶刊九、水刊十、预警期刊 了…

一起看 I/O | Android 性能相关最新动态

作者 / Ben Weiss 过去几年来,我们一直致力于让性能提升工作变得更易上手、回报更高。我们将在本文中分享这一领域的最新发展动态。为您介绍基准配置文件、Android Studio 中的工具改进、库,以及我们如何让这项技术更好地在后台为您服务。此外&#xff0…

IPA50R190CE-ASEMI代理英飞凌MOS管IPA50R190CE

编辑:ll IPA50R190CE-ASEMI代理英飞凌MOS管IPA50R190CE 型号:IPA50R190CE 品牌:Infineon(英飞凌) 封装:TO-220F 最大漏源电流:24.8A 漏源击穿电压:500V RDS(ON)Max&#xff1…

某oa 11.10 未授权任意文件上传

漏洞简介 之前也对通达 oa 做过比较具体的分析和漏洞挖掘,前几天看到通达 oa 11.10 存在未授权任意文件上传漏洞,于是也打算对此进行复现和分析。 环境搭建 https://www.tongda2000.com/download/p2019.php 下载地址 :https://cdndown.tongda…

java-Lambde和方法引用

java-Lambde和方法引用 一、Lambda表达式 1.1 Lambda标准格式 格式: ​ (形参) -> {代码块} 形参:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可 ->:由英文中画线和大于符号组成&#…

企业虚拟机服务器中了lockbit3.0勒索病毒怎么办,lockbit勒索病毒解密

虚拟机服务器在现代企业中扮演着至关重要的角色,它是一个重要的基础设施,用于支持大量的业务应用和数据存储。然而,随着网络攻击技术的不断发展,企业虚拟机服务器也面临着来自黑客的威胁。其中一种最具破坏性的攻击是勒索病毒&…

单例模式8种写法

0. 为什么需要单例模式? 节省内存和计算保证结果正确方便管理 使用场景: 1. 饿汉式(静态常量)—推荐指数:★★☆☆☆ 优点:不会有线程安全问题。 缺点:在类加载的时候就创建对象,…

VMware SD-WAN 5.2 发布 - 软件定义的 WAN

VMware SD-WAN 5.2 发布 - 软件定义的 WAN SD-WAN 解决方案的领导者 请访问原文链接:https://sysin.org/blog/vmware-sd-wan-5/,查看最新版。原创作品,转载请保留出处。 作者主页:sysin.org 产品概述 软件定义的 WAN (SD-WAN)…

chatgpt赋能python:Python列表横向合并

Python列表横向合并 Python是一种功能强大的编程语言,被越来越多的开发者所青睐。列表是Python中最常用的数据结构之一,它是一种有序的集合,可以存储任意类型的数据。在编写Python程序时,很常见的需求是将两个或多个列表横向合并…

(超详细)关于Nacos的共享配置( shared-configs)和拓展配置(extension-config)

前言 用SpringBoot的铁子们,相信大多数人都使用过Nacos作为注册中心和配置文件管理中心,确实很方便。但是很多铁子们依葫芦画瓢,都知道怎么用,但是对于其中的细节可能没有系统地整理过。今天就讲讲关于Nacos的共享配置和扩展配置…