Java技术栈 —— JVM虚拟机

JVM虚拟机

  • 一、字节码(Byte-Code)
    • 1.1 如何查看字节码?
    • 1.2 如何理解字节码的作用?
  • 二、JVM内存模型(极其重点,必须牢牢把握住)
    • 2.1 方法区
    • 2.2 虚拟机栈
    • 2.3 本地方法栈
    • 2.4 堆
    • 2.5 程序计数器
    • 2.6 面试必问
  • 三、GC机制
  • 四、JVM执行引擎
    • 4.1 解释器与JIT(Just-In-Time)编译器
    • 4.2 双亲委派和类加载器

一、字节码(Byte-Code)

1.1 如何查看字节码?

字节码是一种中间状态的二进制文件,由JVM虚拟机生成,方便跨平台执行,在我看来,这其实类似于C/C++里的汇编语言,事实上我们看到的字节码的形式,也确实类似于汇编,那么如何查看字节码呢?比如下面的这份文件,经过JVM的处理,字节码长什么样子?

//Main.java
public class Main{
	public static void main(String[] args){
        System.out.println("Hello World");
	}
}

(1) 找到对应的.class文件。
(2) 反编译该.class文件。
或者IDEA使用 jclasslib Bytecode viewer.

一、参考文章
[1] 《查看java字节码 java查看字节码命令》
[2] 《Java字节码分析快速入门/字节码执行分析(一)》

1.2 如何理解字节码的作用?

其实字节码的目的就是为了实现Java的一次编译,到处运行,各种操作系统和硬件的特性都对应OS的JVM给屏蔽了。

二、JVM内存模型(极其重点,必须牢牢把握住)

2.1 方法区

它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

2.2 虚拟机栈

与程序计数器一样,Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同

2.3 本地方法栈

本地方法栈(Native Method Stack)与虚拟机栈所发挥的作

2.4 堆

堆内存区域,在JVM启动时创建。堆也是Java GC管理的主要区域,因此很多时候也被称做“GC堆”,堆内存也是可以扩展的,通过-Xmx(堆内存初始值)和-Xms(堆内存最大值)参数进行控制。[5]

2.5 程序计数器

程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器

2.6 面试必问

Q1:在Java中,String s = "abc"String s = new String("abc")的区别是什么
根据上述知识点,
String s = "abc"是创建在方法区Method Area中,也就是运行时常量池中的,
String s = new String("abc")是创建在堆Heap内存区域中的。
使用字符串常量的方式创建字符串对象更高效,因为它可以共享相同字符串对象,减少内存消耗。
使用 new String() 方式创建字符串对象会创建新的对象,但在某些情况下,如需要修改字符串内容时,可能会更有用。
需要注意的是,对于字符串的拼接操作,如 String s1 = “ab” + “c”,Java 会自动优化为使用字符串常量的方式创建字符串对象,以避免不必要的对象创建。
Q2:在Java中,String s = new String("abc")创建了几个对象
两个。
首先,"abc"是一个字符串常量,它会被存储在字符串常量池中。当创建多个相同的字符串常量时,它们会共享同一个字符串对象,以节省内存空间。
然后,执行new String("abc")时,会在堆上创建一个新的字符串对象。这个对象是通过调用String类的构造函数创建的,注意,new String("abc")和常量池中的"abc"没关系

public class StringTest {
    public static void main(String[] args) {
        String a1 = "abc";
        String a2 = "abc";
        String b1 = new String("abc");
        String b2 = new String("abc");

	    //需要注意的是,System.identityHashCode方法返回的哈希码并不是对象在内存中的真实地址,而是对象的唯一标识。在不同的时间或不同的环境中,同一个对象可能会有不同的哈希码。因此,通过哈希码来获取对象的地址是不准确的,仅用于调试或演示目的。
        System.out.println(Integer.toHexString(System.identityHashCode(a1)));
        System.out.println(Integer.toHexString(System.identityHashCode(a2)));
        System.out.println(Integer.toHexString(System.identityHashCode(b1)));
        System.out.println(Integer.toHexString(System.identityHashCode(b2)));
//        System.out.println(Integer.toHexString(System.identityHashCode(b1.value))); //debug去看b1.value的地址,和a不一样
//        System.out.println(Integer.toHexString(System.identityHashCode(b2.value))); //debug去看b2.value的地址,和a不一样,但是和b1.value一样


        System.out.println(a1==a2); //true
        System.out.println(a1==b1); //false
        System.out.println(a2==b2); //false
        System.out.println(b1==b2); //false
    }
}
二、参考文章
[1] 《好文推荐:JVM之内存模型》
[2] 【[程序员5分钟] 白话JVM内存结构,死也忘不了】- bilibili
[3] [《深入理解Java虚拟机 - JVM高级特性与最佳实践》第2.2节运行时数据区域]
[4] Chapter 2. The Structure of the Java Virtual Machine - Oracle
[5] 《Java 参数 -Xms 和 -Xmx》 - CSDN
[6] 从String s = new String(“abc”)了解引用变量与对象 - 博客园

三、GC机制

简单的有引用计数与可达性算法,不同的虚拟机,会实现具有各自虚拟机特色的GC算法,就看各种虚拟机更关注哪方面内容了。

三、参考文章
[1] 《初学Java垃圾回收机制 》- 微信公众号

四、JVM执行引擎

4.1 解释器与JIT(Just-In-Time)编译器

(1)解释器。解释执行
(2)JIT编译器。就是虚拟机将源代码直接编译成和本地机器平台相关的汇编语言,通过汇编生成机器代码。
一般来说,都是二者混着用。
在这里插入图片描述

Q1:如何让JVM只使用解释器或JIT编译器?

programmer@pc-ubuntu:~$ java -version
openjdk version "1.8.0_392"
OpenJDK Runtime Environment (build 1.8.0_392-8u392-ga-1~22.04-b08)
OpenJDK 64-Bit Server VM (build 25.392-b08, mixed mode) # 默认。平常从来没注意这里是mixed mode
programmer@pc-ubuntu:~$ java -Xint -version
openjdk version "1.8.0_392"
OpenJDK Runtime Environment (build 1.8.0_392-8u392-ga-1~22.04-b08)
OpenJDK 64-Bit Server VM (build 25.392-b08, interpreted mode) # interpreted
programmer@pc-ubuntu:~$ java -Xcomp -version
openjdk version "1.8.0_392"
OpenJDK Runtime Environment (build 1.8.0_392-8u392-ga-1~22.04-b08)
OpenJDK 64-Bit Server VM (build 25.392-b08, compiled mode) # compiled

Q2:如何使用JIT编译器的Client(关注局部)与Server编译优化(关注全局)?
首先随便写个Hello World的代码,然后用Javac命令加上参数。

$ javac -client HelloWorld.java 
$ javac -server HelloWorld.java
$ javap -c HelloWorld.class # 你如果要看编译后的代码文件可以用这个命令

现在,你应该找到了一点以前车间老工人师傅调试机器的感觉了。

4.1 参考文章
[1] 重点阅读,写的非常好 《深入理解JVM(七)一一执行引擎(解释器和JIT编译器) 》- 稀土掘金
[2] 《Java解释器和编译器》- 知乎
[3] The JIT compiler - IBM

4.2 双亲委派和类加载器

为什么叫双亲委派,这个双体现在哪?英文是Parent Delegation Mechanism,字面意思是父委派机制,双亲委派谁翻译的?双亲体现在,子级类加载器先委派给父级类加载器,父级类加载器加载不了再派给子类。
在这里插入图片描述

4.2 参考文章
[1] 《你确定你真的理解"双亲委派"了吗?!》- 博客园
[2] 《Java双亲委派模型:为什么要双亲委派?如何打破它?破在哪里?》- CSDN

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【华为 ICT HCIA eNSP 习题汇总】——题目集7

1、一台 PC 的 MAC 地址是 5489-98FB-65D8 ,管理员希望该 PC 从 DHCP 服务器获得指定的 IP 地址为192.168.1.11/24,以下命令配置正确的是()。 A、dhcp static-bind ip-address 192.168.1.11 24 mac- address 5489-98FB-65D8 B、dh…

力扣740. 删除并获得点数

动态规划 思路: 选择元素 x,获得其点数,删除 x 1 和 x - 1,则其他的 x 的点数也会被获得;可以将数组转换成一个有序 map,key 为 x, value 为对应所有 x 的和;则问题转换成了不能同…

中间件-缓存、索引、日志

文章目录 缓存中间件本地缓存中间件分布式缓存中间件全文索引中间件分布式日志中间件小结 缓存中间件 缓存是性能优化的一大利器 我们先一起来看一个用户中心查询用户信息的基本流程 这时候,如果查找用户信息这个 API 的调用频率增加,并且在整个业务流…

怎么使用【jmeter正则表达式提取器】解决返回值作参数的问题

前言 我们在使用jmeter做接口测试时,常常会碰到上个接口的返回值会作为下个接口的参数来进行请求。这时候,就需要用到jmeter的正则表达式提取器了。 添加正则表达式提取器步骤: “选择要添加提取器的接口右键”——add——post processors—…

线程池--JAVA

虽然线程是轻量级进程,但是如果当创建和销毁的的频率非常之高,那么它也就会消耗很多的资源。 而线程池就是用来优化线程频繁创建和销毁的场景,减少线程创建、销毁的频率。 ExecutorService JAVA标准库为我们实现了线程池,Execu…

archlinux 如何解决安装以后没有声音的问题

今天安装完archlinux以后发现看视频没声音 检查一下是否有 /lib/firmware/intel/sof 发现没有 如果你也是这样的话,可以尝试安装: sudo pacman -S sof-firmware 重启后再看看有没有声音: reboot 反正我有声音了

跟着我学Python进阶篇:03. 面向对象(下)

往期文章 跟着我学Python基础篇:01.初露端倪 跟着我学Python基础篇:02.数字与字符串编程 跟着我学Python基础篇:03.选择结构 跟着我学Python基础篇:04.循环 跟着我学Python基础篇:05.函数 跟着我学Python基础篇&#…

【ARM 嵌入式 编译系列 7.3 -- GCC 链接脚本中 DISCARD 与 .ARM.exidx】

请阅读【嵌入式开发学习必备专栏 之 ARM GCC 编译专栏】 文章目录 背景.ARM.exidx方法一:使用链接器脚本方法二:使用链接器选项注意事项背景 在移植 RT-Thread 到 cortex-m33(RA4M2)上的时候,在编译的时候遇到下面问题: Building target: ra4m2.elf arm

Vue2基础-Vue对象进阶介绍2

文章目录 一、自定义指令1、用法2、注意点 二、生命周期1、概念2、示意图3、分析 一、自定义指令 本质上是封装了DOM元素的具体操作 1、用法 <div >放大十倍后的值是&#xff1a;<span v-big"n"></span></div> <input type"text&…

【Linux】—— 共享内存

本期我将要带大家学习的是有关进程间通信的另一种方式——共享内存。共享内存是一种用于进程间通信的高效机制&#xff0c;允许多个进程访问和操作同一块内存区域。 目录 &#xff08;一&#xff09;深刻理解共享内存 1.1 概念解释 1.2 共享内存原理 1.3 共享内存数据结构 …

Spring | Srping AOP (AOP简介、动态代理、基于“代理类”的AOP实现)

目录: 1.Spring AOP简介1.1 AOP简介1.2 AOP术语 2.动态代理2.1 JDK动态代理2.2 CGLIB代理 3.基于“代理类”的AOP实现3.1 Spring的通知类型3.2 ProxyFactoryBean ( 可通知.xml配置文件完成aop功能 ) 1.Spring AOP简介 1.1 AOP简介 Spring的AOP模块&#xff0c;是Spring框架体系…

【C++】list容器迭代器的模拟实现

list容器内部基本都是链表形式实现&#xff0c;这里的迭代器实现的逻辑需要注意C语言中指针的转换。 list容器如同数据结构中的队列&#xff0c;通常用链式结构进行存储。在这个容器中&#xff0c;我们可以模仿系统的逻辑&#xff0c;在头结点后设置一个“ 哨兵 ”&#xff0c;…

什么勒索攻击,应该如何防护?

当前&#xff0c;勒索攻击、僵尸网络攻击、DDos攻击、APT攻击、挖矿攻击、供应链攻击、网站攻击、电信诈骗等各种攻击手段层出不穷。 勒索攻击应该是今年网络安全行业讨论最多的话题&#xff0c;勒索钱财或者窃取商业数据是黑产最主要的目的。 勒索软件的攻击特征 与其它攻击行…

限价单和止损单是什么?澳福实例讲解

什么是限价单和止损单&#xff0c;投资者如何使用它?了解交易基础知识&#xff0c;快速进入市场盈利收场&#xff0c;今天fpmarkets澳福和各位投资者继续探讨交易基础知识。 止损单是在看涨趋势中以更高的价格买入的前提&#xff0c;通过图表得知&#xff0c;黄线显示欧元兑美…

刷题 ------ 排序

文章目录 1.K 次取返后最大化的数组和&#xff08;堆&#xff09;2.数组的相对排序&#xff08;桶&#xff09;3.最小绝对差4.根据数字二进制下1的数目排序&#xff08;qsort&#xff09;5.有多少小于当前数字的数字6.非递增顺序的最小子序列7.按照频率将数组升序排序&#xff…

生成当天递增唯一的流水号的几种方式

说明&#xff1a;当开发中&#xff0c;如交易、文件传输过程中的文件名&#xff0c;可能需要我们使用一串唯一的数字来锁定这一条“交互记录”&#xff0c;即流水号。 本文介绍几种生成6位递增唯一&#xff0c;且每日重置的流水号的方式。 方式一&#xff1a;使用Redis 我们…

Leetcode—22.括号生成【中等】

2023每日刷题&#xff08;七十九&#xff09; Leetcode—22.括号生成 算法思想 实现代码 class Solution { public:vector<string> generateParenthesis(int n) {vector<string> ans;int m n * 2;string path(m, 0);function<void(int, int)> dfs [&…

自己构建webpack+vue3+ts

先看看我的目录结构&#xff08;我全局使用TS&#xff09;&#xff1a; 一、安装配置webpack打包 安装esno npm install esnoesno 是基于 esbuild 的 TS/ESNext node 运行时,有了它&#xff0c;就可以直接通过esno *.ts的方式启动脚本&#xff0c;package.json中添加 type:…

力扣62. 不同路径

动态规划 思路&#xff1a; 定义 dp[r][c] 为到达坐标 (r, c) 的路径数&#xff1a; 它只能有同一行左边相邻方格向右到达或者同一列上方相邻方格向下到达&#xff1b;状态转移方程&#xff1a; dp[r][c] dp[r][c - 1] dp[r - 1][c]初始状态 dp[0][0] 1第一行的路径数是 1第…

二维码地址门牌管理系统:社区新风向

文章目录 前言一、集成先进技术的系统二、便捷居民体验三、支持社区管理四、未来展望与可扩展性 前言 随着科技的不断发展&#xff0c;智能化管理已经深入到我们的生活中。二维码门牌管理系统作为一款创新产品&#xff0c;在社区管理领域迅速引起广泛关注。这款系统不仅提升了…