jvm知识梳理

2023-10-27

1.java虚拟机的组成

java虚拟机主要由四部分组成

(1)ClassLoader:按特定格式加载class文件到内存中

(2)runtime data area:jvm内存空间模型

(3)execution engine:命令解析器

(4)native interface:融合不同开发语言的原生库供java使用

2.类加载过程

(1)编译器把.java文件编译成.class文件

(2)ClassLoader将.class文件加载到内存中,生成class<T>对象

(3)jvm根据class<T>生成对应的实体类对象

3.谈谈ClassLoader

ClassLoader负责将系统外部的class二进制数据流加载到jvm中,再由jvm进行连接/初始化。ClassLoader是一个抽象类,通过loadClass()方法加载类,ClassLoader的一般实现类有四个,即

(1)BootStrapClassLoader:由C++编写的基础类加载器,用于加载java.*下的核心类,加载路径是jre\lib\rt.jar或者系统变量Xbootclasspath下的类。源码不可见

(2)ExtClassLoader:由java编写的用于加载java扩展类javax.*下的类,加载路径是jre\ext\*.jar或系统变量Djava.ext.dirs下的类。 可以查看源码

(3)AppClassLoader:由java编写,用于加载工程目录下的类,加载路径是CLASSPATH或系统变量Djava.class.path下的类。 可以查看源码

(4)自定义ClassLoader:用户自己编写的(需继承ClassLoader),定制加载

4.双亲委派机制

在加载一个类时,步骤如下:

先判断此类是否已被加载,已加载则直接返回,未加载则从下至上继续判断

(1)判断是否已被自定义ClassLoader加载

(2)若未被自定义ClassLoader加载,则判断是否被AppClassLoader加载

(3)若未被AppClassLoader加载,则判断是否被ExtClassLoader加载

(4)若未被ExtClassLoader加载,则判断是否被BootStrapClassLoader加载

若全部加载器判断完,均未加载此类则由BootStrapClassLoader开始从上至下尝试加载

(1)尝试通过BootStrapClassLoader加载

(2)若未能被BootStrapClassLoader加载,则尝试通过ExtClassLoader加载

(3)若未能被ExtClassLoader加载,则尝试通过AppClassLoader加载

(4)若未能被AppClassLoader加载,则尝试通过ClassLoader加载

(5)若所有加载器都未能成功加载,抛出classNotFound异常

5.loadClass和forName区别

先说下类装载和加载的基础知识,类的加载分为隐式加载(new)和显式加载(loadClass和forName),java类的装载过程分为三个阶段。

(1)加载:通过ClasLoader加载class字节码文件,生成class对象

(2)连接:连接分为三个子步骤1校验,校验class文件的正确性和安全性。2准备,为类变量分配存储空间并设置初始值(注意:这里说的类变量是static类型变量,初始值是默认值,比如变量static int a = 111,在此步骤只给赋值0,因为int默认为0,111是在下一步赋值的)。3解析,将jvm常量池中的符号引用转为直接引用。

(3)初始化:进行类变量的复赋值和执行静态代码块

loadClass方法只是实现了上诉第一步,即加载

forName方法实现了全部三个步骤

6.JVM内存模型(jdk8)

由线程私有的:本地方法栈,虚拟机栈,程序计数器

线程公有的:元空间,堆

5部分组成,如图

(1)程序计数器:标识字节码文件执行行号,告诉机器执行哪行代码

(2)虚拟机栈:是java方法执行的内存模型,程序运行时每执行一个方法内存就会分配一定空间作为栈帧(Stack Frame是用于支持虚拟机进行方法调用和方法执行的数据结构),这些栈帧存放在虚拟机栈中,方法执行结束会自动按后进先出的策略释放这些栈帧,因此无需回收。栈帧由局部变量表和操作数栈组成,局部表量表存放方法中的各种局部变量,操作数占是描述方法执行中变量的计算/赋值过程

(3)本地方法栈:与虚拟机栈类似,只不过是针对native方法的栈

(4)元空间:存储class相关信息(class的方法,属性信息等)jdk7及以前,这部分属于永久代,元空间和永久代的本质区别是元空间使用本地内存,永久代使用jvm内存,使用元空间替代永久代有以下如下好处:消灭了outOfMerroryError:permGen space这个异常,之前永久代放在堆中,增加了GC的复杂度,而且类和方法信息大小难以确定,不方便指定永久代大小,永久代设置过大容易造成老年代内存溢出,永久代设置过小容易造成永久代内存溢出。再一点就是orcale有意将hotspot虚拟机和其他JVM集成,但永久代是hotspot特有的,为了方便后续集成去掉永久代

(5)堆:对象实例空间和GC管理的空间

7.为什么递归容易导致stackoverflow

因为调用方法会创建栈针并压如虚拟机栈,递归会不断创建栈针增加栈的深度,而线程的虚拟机栈深度固定,超出就会导致栈溢出

8.JVM核心参数

-Xms:堆的初始值

-Xmx:堆的最大值,在堆内存不足时,会自动扩容至-Xmx的大小,在实际中通常把此值设跟-Xms一样大,因为java堆扩容会发生内存抖动,非常影响机器的稳定性

-Xss:线程虚拟机栈大小,通常256K就够了,此参数影响并发线程数的大

-XX:NewRatio:老年代和年轻代内存大小比例,通常为2,即老年代和年轻代大小比例2:1

9.程序运行时的内存分配策略

静态存储:编译时即能确定运行时的存储空间需求(对应方法区,存class对象,类的static变量)

栈式存储:编译时不能确定,但运行时通过程序入口可确定的存储需求(对应栈,存和方法中的基本类型变量和对象类型的引用)

堆式存储:编译和运行时程序入口都不能确定空间的存储需求(对应堆,存new出来的对象类型)

10.栈和堆的联系和区别

联系:访问对象/数组时,会在栈中创建一个引用变量指向堆中对象/数组,退出方法时引用变量销毁但堆中对象仍然存在,堆中对象若一定时间内没有被引用变量指向则会被回收

区别:1.栈比堆小 2.栈自动释放堆需要GC 3.栈产生的碎片小于堆 4.栈支持静态分配和动态分配,堆只支持动态分配 5.栈的效率比堆高

11.谈谈String的intern方法在jdk6和jdk6以后的区别

方法作用:返回字符串在常量池中地址并赋给调用该方法的对象。

jdk6实现:从字符串常量池中查找,若不存在则在常量池中创建并返回

jdk6以后实现:从字符串常量池中查找,若不存在则进入堆中查找,若堆中存在则在常量池中创建该对象的引用并返回,若堆中也不存则在常量池中穿件并返回

引申练习题:请问下面两段代码输出结果是啥?

String s1=new String("a")+new String("b");
s1.intern();
String s2 = "ab";
System.out.println(s1==s2);//jdk6:false jdk7/jdk8:true
------------------------------------------
String s3=new String("a")+new String("b");
String s4 = "ab";
s1.intern();
System.out.println(s3==s4);//false
------------------------------------------
String s5=new String("a");
s1.intern();
String s6 = "a";
System.out.println(s5==s6);//false

12.GC的标记算法

(1)引用计数法:原理是记录对象被引用的次数,被一个对象引用则计数+1,引用被回收则-1,归0后被回收。优点是计算简单效率高,缺点是无法计算互相引用等场景

(2)可达性分析算法:判断程序中对象的引用链,当对象顺着引用链可被查到时,则认为“可达”,否则将被回收

13.GC的回收算法

(1)标记-清除算法:标记可达的对象,在回收时回收未标记的对象,优点效率高,缺点容易产生内存碎片

(2)标记-整理算法:标记可达的对象,在回收时将可达对象移动到集中的内存区域再进行回收,有点是相比标记清除算法解决了内存碎片的问题,但效率不如标记清除算法

(3)复制算法:将内存分为相等的两块区域,将可达对象标记后复制到另一块区域,然后全量清除原区域空间,优点是避免内存碎片问题,缺点是需要冗余一份内存空间,可达对象越少,采用复制算法越高效,因为复制对象会消耗cpu

(4)分代收集算法:是上诉算法的组合拳,把JVM分为年轻代和老年代,年轻代采取复制算法,老年代采取标记清除/整理算法

年轻代:执行minor GC,分为Eden区和Survivor区(Eden区是大部分对象创建时所在区域,除非内存很大的对象会被直接创建到老年代,Survivor区又分为from区和to区,这三个区的默认大小比例是8:1:1可在jvm参数-XX:SurvivorRatio设置Eden区和Survivor的比例),采用复制算法,具体执行过程为

第一步:标记Eden区和from区中可达对象

第二步:将上诉两区可达对象复制到to区,并将标记“年龄”加1,年龄超过15则存入老年代(15是默认,可在jvm参数-XX:+PretenuerSizeThreshold中配置)。当to区装不下复制结果时,也会将一部分对象直接放到老年代

第三步:将Eden区和from区清空,将原from区标记为下一次执行GC的to区,原to区反之

老年代:存放生命周期较长的对象,执行Full GC和Major GC,采用标记清除/标记整理算法

14.java中强引用,软引用,弱引用,虚引用的区别和作用

软引用:主要用途是做内存缓存,内存不足时回收,缓解内存不足导致OOM的问题

弱引用:比软引用更弱些,用于标记些偶尔使用的对象,会跟随GC被回收

虚引用:最弱的引用,用于跟随对象被垃圾回收器回收,哨兵作用

15.jvm两种运行模式

(1)Servier:启动较慢,但稳定运行后速度快

(2)Client:启动较快,但运行稳定后速度慢

16.垃圾收集器

(1)年轻代垃圾收集器

Serial收集器:采用复制算法,单线程收集,通过-XX:+UseSerialGC设置,此收集器简单高效,注重缩短stop-the-world的时间,提升用户体验,是Client模式下默认的年轻代收集器

ParNew收集器:Serial收集器的多线程版本(通过-XX:+UseParNewGC设置),特点与Serial收集器相同,在单核环境下效率不如Serial收集器,与Serial收集器是唯二的可以跟cms收集器共同工作的年轻代收集器,默认线程数是系统核数,可通过jvm参数修改

Parallel Scavenge收集器:通过-XX:+UseParallelGC设置,同样是多线程的采用复制算法的收集器,该收集器更注重提高系统吞吐量,适合后台跑定时任务之类的应用,是Server模式下默认的年轻代收集器

(2)老年代垃圾收集器

Serial Old收集器:采用标记-整理算法,单线程收集,通过-XX:UseSerialOldGC设置,Client模式下默认的老年代收集器,可搭配任何年轻代收集器使用

Patralled Old收集器:采用标记-整理算法,多线程收集,吞吐量优先,搭配年轻代的Parallel Scavenge使用,通过-XX:+UseParalledOldGC设置

CMS收集器:采用标记-清除算法,通过-XX:+UseConcMarkSweepGC设置,是常用的老年代收集器。

G1(Garbage First)收集器:同时用于年轻代和老年代,特点是会将整个java堆内存划分成多个大小相等的Regin,年轻代和老年代不再物理隔离

G1有如下优势:

1.并发和并行:G1可以用多个CPU来缩短stop-the-world

2.分代收集:虽然年轻代和老年代不再物理隔离,但仍然独立处理新对象和存活已久的老对象

3.空间整合:因为基于标记-整理算法,解决了很多其他老年代收集器内存不连续问题

4.可预测的停顿:因为支持配置垃圾收集所占用时间在N毫秒内

17.对象从年轻代晋升到老年代的场景

(1)对象过大,直接创建到老年代

(2)可达性算法计数年龄达到阈值(默认15)

(3)动态对象年龄判定:当 Survivor 空间中相同年龄所有对象的大小总和大于 Survivor 空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,而不需要达到默认的分代年龄

18.触发full GC的条件

(1)老年代空间不足

(2)永久代(如有)空间不足

(3)gc 担保失败,逻辑如下图

(4)程序中的Sysyem.gc()

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

jvm知识梳理 的相关文章

  • 埃拉托色尼筛法 - 实现返回一些非质数值?

    我用 Java 实现了埃拉托斯特尼筛法 通过伪代码 public static void sieveofEratosthenes int n boolean numArray numArray new boolean n for int i
  • Android 中 localTime 和 localDate 的替代类有哪些? [复制]

    这个问题在这里已经有答案了 我想使用从 android API 获得的长值 该值将日期返回为长值 表示为自纪元以来的毫秒数 我需要使用像 isBefore plusDays isAfter 这样的方法 Cursor managedCurso
  • tomcat 7.0.50 java websocket 实现给出 404 错误

    我正在尝试使用 Java Websocket API 1 0 JSR 356 中指定的带注释端点在 tomcat 7 0 50 上实现 websocket 以下是我如何对其进行编码的简要步骤 1 使用 ServerEndpoint注解编写w
  • 为什么 MOVE CURSOR 在 OS X Mountain Lion 上不显示?

    我正在做一个项目 想看看 Swing 提供的每个光标是什么样子的 public class Test public static void main String args JFrame frame new JFrame frame set
  • 如何检测图像是否像素化

    之前有人在 SO 上提出过这样的问题 在Python中检测像素化图像 https stackoverflow com questions 12942365 detecting a pixelated image in python还有关于q
  • 如何使用正则表达式验证 1-99 范围?

    我需要验证一些用户输入 以确保输入的数字在 1 99 范围内 含 这些必须是整数 Integer 值 允许前面加 0 但可选 有效值 1 01 10 99 09 无效值 0 007 100 10 5 010 到目前为止 我已经制定了以下正则
  • 虽然我的类已加载,但 Class.forName 抛出 ClassNotFoundException

    代码如下 它的作用是加载我放在主目录中的 jar 文件中的所有类 import java io File import java util jar JarFile import java util jar JarEntry import j
  • 当 minifyEnabled 为 true 时 Android 应用程序崩溃

    我正在使用多模块应用程序 并且该应用程序崩溃时minifyEnabled true in the installed模块的build gradle 以下是从游戏控制台检索到的反混淆堆栈跟踪 FATAL EXCEPTION Controlle
  • 通过 appassembler-maven-plugin 生成的脚本无法在 Spring Boot 应用程序中找到主类

    我使用 appassembler maven plugin 生成的启动脚本有问题 我有一个基本的 spring boot 应用程序 只有一个类 SpringBootApplication public class ScriptDemoApp
  • 我们如何测试包私有类?

    我正在看书Effective Java in Item 13 Minimize the accessibility of classes and members 它提到 为了方便测试 您可能想让类 接口或成员更易于访问 这在某种程度上是好的
  • 如何停止执行的 Jar 文件

    这感觉像是一个愚蠢的问题 但我似乎无法弄清楚 当我在 Windows 上运行 jar 文件时 它不会出现在任务管理器进程中 我怎样才能终止它 我已经尝试过 TASKKILL 但它对我也不起作用 On Linux ps ef grep jav
  • Play.application() 的替代方案是什么

    我是 Play 框架的新手 我想读取conf文件夹中的一个文件 所以我用了Play application classloader getResources Data json nextElement getFile 但我知道 play P
  • Lombok @Builder 不创建不可变对象?

    在很多网站上 我看到 lombok Builder 可以用来创建不可变的对象 https www baeldung com lombok builder singular https www baeldung com lombok buil
  • 使用Java绘制维恩图

    我正在尝试根据给定的布尔方程绘制维恩图 例如 a AND b AND c我想在 Android 手机上执行此操作 因此我需要找到一种使用 Java 来执行此操作的方法 我找到了一个完美的小部件 它可以完成我在这方面寻找的一切布尔代数计算器
  • Hadoop NoSuchMethodError apache.commons.cli

    我在用着hadoop 2 7 2我用 IntelliJ 做了一个 MapReduce 工作 在我的工作中 我正在使用apache commons cli 1 3 1我把库放在罐子里 当我在 Hadoop 集群上使用 MapReduceJob
  • 使用 Java https 上传到 Imgur v3 错误

    我目前正在尝试使用他们当前的 API v3 上传到 imgur 但是我不断收到错误 错误 javax net ssl SSLException 证书中的主机名不匹配 api imgur com imgur com OR imgur com
  • Java 的 PriorityQueue 与最小堆有何不同?

    他们为什么命名PriorityQueue如果你不能插入优先级 它看起来与堆非常相似 有什么区别吗 如果没有区别那为什么叫它PriorityQueue而不是堆 默认的PriorityQueue是用Min Heap实现的 即栈顶元素是堆中最小的
  • HttpClient请求设置属性问题

    我使用这个 HttpClient 库玩了一段时间 几周 我想以某种方式将属性设置为请求 不是参数而是属性 在我的 servlet 中 我想使用 Integer inte Integer request getAttribute obj 我不
  • 将对象从手机共享到 Android Wear

    我创建了一个应用程序 在此应用程序中 您拥有包含 2 个字符串 姓名和年龄 和一个位图 头像 的对象 所有内容都保存到 sqlite 数据库中 现在我希望可以在我的智能手表上访问这些对象 所以我想实现的是你可以去启动 启动应用程序并向左和向
  • 即使调整大小,如何获得屏幕的精确中间位置

    好的 这个问题有两部分 当我做一个JFrame 并在其上画一些东西 即使我将宽度设置为 400 并使其在一个项目击中它时 当然 允许项目宽度 它会反弹回来 但由于某种原因 它总是偏离屏幕约 10 个像素 有没有办法解决这个问题 或者我只需要

随机推荐

  • 钉钉微应用开发调试

    1 下载安卓调试包 2 安卓手机点击 设置 开发者选项 USB调试 3 打开钉钉 设置 通用 开发者选项 微应用调试 4 手机连接到电脑 打开chrome chrome inspect 开始调试 如果chrome inspect显示错误页面
  • 超声波模块的使用

    C SR04超声波测距模块可提供约2cm400厘米的非接触式距离感测功能 测距精度可达高到3毫米 模块包括超声波发射器 接收器与控制电路像智能小车的测距以及转向 或是一些项目中 常常会用到 智能小车测距可以及时发现前方的障碍物 使智能小车可
  • 【Unity3D】在Unity中使用Protobuf(proto3)

    有研究表明 一条消息数据 用protobuf序列化后的大小是json的10分之一 xml格式的20分之一 是二进制序列化的10分之一 ProtoBuf的优势还是很明显的 这里简单介绍哈使用 一 下载protobuf https github
  • css移动端页面单位,移动端web开发PX单位问题

    在页面开发过程中 对于设计给的设计稿 一般的PC页面开发的时候 很简单 使用px为单位 给多少px就标注多少 但是到了移动端的web开发 一般标注的单位是dp 这对于css里面px单位就需要转换一下了 这边简单说明一下相关点 几个概念 设备
  • linux启动/重启mongo时报错$OPTIONS (code=exited, status=14)

    遇到过多次这个问题 在此记录一下 网上查了很多 但关于为什么原本好好的 mongo 会报此类错误的原因分析的文章并不多 目前发现 没有正确退出 mongo mongo 配置文件修改错误 修改 mongo 配置文件后重启 等 都有可能导致 m
  • shift用计算机,shift是什么意思_shift键有什么用? - 学无忧

    在我们的电脑键盘上有一个shift上档键 shift是什么意思 shift键有什么用 经常使用电脑的人都会用到这个shift键 这个键跟ctrl和atl键都是很常用的按键 学无忧就来针对shfit来具体讲解 shift是什么意思 shift
  • Mysql 联合索引最左匹配原则

    最左前缀匹配原则 在MySQL建立联合索引时会遵守最左前缀匹配原则 即最左优先 在检索数据时从联合索引的最左边开始匹配 Mysql会一直向右匹配直到遇到范围查询 gt lt between like 就停止匹配了 就比如 a 3 and b
  • 算法学习笔记:labuladong--滑动窗口

    算法技巧的思路非常简单 就是维护一个窗口 不断滑动 然后更新答案 int left 0 right 0 while right lt s size 增大窗口 window add s right right while window nee
  • Python中 sys.argv[]的用法简明解释

    因为是看书自学的python 开始后不久就遇到了这个引入的模块函数 且一直在IDLE上编辑了后运行 试图从结果发现它的用途 然而结果一直都是没结果 也在网上查了许多 但发现这个问题的比较详细的解释只有一个版本 大部分都是转载和复制的 给的都
  • 大数据入门学习

    https www cnblogs com xing901022 p 6195422 html
  • redis之list基本操作

    我们存多个数据用hash的时候它是没有顺序的 我们平时操作 实际上数据很多情况下都是有顺序的 那有没有一种能够用来存储带有顺序的这种数据模型呢 list就专门来干这事儿 一 list类型 数据存储需求 存储多个数据 并对数据进入存储空间的顺
  • 常用的两个免费可以商用的cc0协议图片网站

    什么是CC0协议CC0是CC协议 知识共享 是Creative Commons在中国大陆地区的通用译名 一般简称为CC CC既是该国际组织的名称缩写 也是一种版权授权协议的统称 以外的一种新的版权声明协议 采用该协议即代表作者宣布放弃该创作
  • ROS Noetic版本 rosdep找不到命令 不能使用的解决方法

    使用rosdep指令来安装开源包所需的依赖是很方便的 本文主要介绍ROS Noetic版本中使用rosdep 报错找不到命令 rosdep不能使用的解决方法 rosdep 找不到命令 Command rosdep not found but
  • nginx 中文url rewrite 404

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 原料 nginx with debug或openresty 背景 项目中有用户图片库需求 允许用户自定义文件夹 然后上传图片到该文件夹 当用户自定义的文件夹为中文或者访问u
  • 微信第三方平台之代开发小程序(二)

    第二部分 快速创建小程序 必须全网发布成功 注 第一部分 全网发布前的准备 请看我前面的文章 1 权限集准备 全网发布成功后才可生效 2 第三方收集法人微信 法人姓名 企业名称 信用代码四个商户信息外加第三方客服电话 3 企业名称需与工商部
  • 【python教程入门学习】Python教程第1篇:下载和安装Python

    Python是当下流行的通用编程语言 简单易学 容易上手 且 钱 景广阔 在网络爬虫 数据挖掘分析 人工智能 运营运维 日常工作效率提升 无不有Python的影子 因此 今天跟大家分享Python的下载和安装教程 第一步 下载Python最
  • 域名服务详解(域名解析流程和分类)

    一 基本概念 访问互联网是依靠IP地址的 但IP地址多种多样 很难记忆 所以使用域名服务 代替IP地址输入 1 hosts文件 1 位置 Windows系统在C Windows System32 drivers etc hosts 需要超级
  • usdt充值btc网络(非节点钱包地址)

    1 此充值具有一定的交易风险 请一定做好判断 步骤 用户绑定其他交易所的地址 往平台充值 只能使用用户绑定的钱包地址充值 否则无法确认充值成功 用户先填写充值金额 gt 生成充值订单 gt 通过平台设置的收币钱包地址充值 gt 填写充值产生
  • ReactNative组件生命周期

    组件生命周期详解 组件生命周期基础知识 组件 又名控件 是一段独立可复用的代码 在React Native应用开发中 组件是页面最基本的组成部分 和React的组件一样 RN的组件也有自己的生命周期 在RN应用开发中 组件的生命周期指组件初
  • jvm知识梳理

    1 java虚拟机的组成 java虚拟机主要由四部分组成 1 ClassLoader 按特定格式加载class文件到内存中 2 runtime data area jvm内存空间模型 3 execution engine 命令解析器 4 n