快速了解Java虚拟机(JVM)以及常见面试题(持续更新中......)

简介: JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。

一、JVM相关概念汇总

1.png

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。


引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。


1、JVM内存图

2.png


2、JVM类加载器

在类加载阶段,通过一个类的全限定名来获取描述该类的二进制字节流的这个动作的“代码”被称为“类加载器”(Class Loader),这个动作是可以自定义实现的。


类加载器也是一段程序,一段代码,代码可能是c或c++、Java所编写,主要是读取磁盘下或jar包中的Class文件,装载到jvm中


虚拟机自带的类加载器

启动类加载器(rt.jar) 根加载器 C++实现的

扩展类加载器 (扩展的类)extends ClassLoader

应用程序加载器(自己写的类) extends ClassLoader


3、双亲委派模型


如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成。


每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载器中。只有当上一层类加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到这个类)时,下一层类加载器才会尝试自己去加载。


三个加载器都加载不到就会抛出 ClassNotFund异常


JDK设计双亲委派模型的好处:


确保安全,避免核心类库被修改

避免重复加载

保证类的唯一性。

双亲委派模型可以被打破,需要自定义类加载器,继承ClassLoader类,重写LoadClass方法。


1.png


native:

使用native关键字时,会去调用底层的c语言的库

进入本地方法栈,调用本地方法的本地接口 JIN

JIN作用:扩展java的使用,融合不同的语言为java所有


方法区主要存放:静态变量,常量,类信息,常量池。


4、堆


一个JVM只有一个堆内存,堆内存大小可以调节。


类加载器读取了类文件会把,类,方法,常量,变量,保存所有引用类型的真实对象。


堆内存主要分为三个区域:新生区(伊甸园)、老年区、永久区。


堆、元空间(方法区)是线程共享的;其他区域是线程私有的


1.png


特点及作用:


1、线程共享的一块区域;


2、虚拟机启动时创建;


3、虚拟机所管理的内存中最大的一块区域;


4、存放所有实例对象或数组;


5、GC垃圾收集器的主要管理区域;


6、可分为新生代、老年代;


7、新生代更细化可分为Eden、

From Survivor、To Survivor,Eden:Survivor = 8:1:1


8、可通过-Xmx、-Xms调节堆大小;


9、无法再扩展


java.lang.OutOfMemoryError: Java heap space


GC垃圾回收机制:主要回收新生区和老年区


堆内存满,抛出,OOM错误。 JDK8之前叫永久存储区,JDK8之后叫元空间。 逻辑上存在,物理上不存在


新生区:


类诞生和成长,直到死亡的地方

所有的对象都在伊甸园区new出来

老年代:

·当新生代经历15次轻GC后还存在引用的,则被转移到老年代


永久区:


永久区常驻内存,用来存放JDK自身携带的Class对象,interface元数据,存储的是Java运行的一些环境,这个区域不存在垃圾回收。关闭虚拟机时,释放这个区域的内存。


OOM:


-Xms:设置初始化分配内存大小 1/64 -Xmx:设置最大分配内存1/4


-XX:+PrintGCDetails GC清理垃圾信息 -XX:+HeapDumpOnOutOfMemoryError dumpOOM错误文件


尝试扩大内存空间看结果,如果还有错误,分析代码是否出现垃圾代码或者死循环。


内存快照分析工具,MAT,Jprofiler 作用:


①分析Dump内存文件,快速定位内存泄漏 ②获得堆中数据 ③获得最大对象


5、GC


作用区域:堆(堆+方法区(非堆)))


GC两种类型:轻GC 针对新生代和偶尔的幸存区(from,to) 重GC(全局GC)


GC的算法:标记清除法 不需要额外内存空间,两次扫描,浪费时间,产生内存碎片 、标记压缩,复制算法(新生代、伊甸园区 )伊甸园区和to区为空,引用计数器


GC算法总结:


内存效率:复制算法>标记清除算法>标记压缩算法(时间复杂度)


内存整齐度:复制算法=标记压缩算法>标记清除


内存利用率:标记压缩算法=标记清除>复制算法


新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?


新生代回收器:Serial、ParNew、Parallel Scavenge

老年代回收器:Serial Old、Parallel Old、CMS

整堆回收器:G1

新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;老年代回收器一般采用的是标记-整理的算法进行垃圾回收。


6、栈


特点及其作用:


1、线程私有;


2、方法执行会创建栈帧,存储局部变量表等信息;


3、方法执行入虚拟机栈,方法执行完出虚拟机栈;(先进后出)


4、栈深度大于虚拟机所允许StackOverflowError;


5、栈需扩展而无法申请空间OutOfMemoryError(比较少见);hotspot虚拟机没有;


6、栈里面运行方法,存放方法的局部变量名,变量名所指向的值(常量值、对象值等)都存放到堆上的;


7、栈一般都不设置大小,栈所占的空间其实很小,可以通过-Xss1M进行设置,如果不设置默认为1M;


8、随线程而生,随线程而灭;


9、该区域不会有GC回收。


二 、JVM面试总结


1、Java运行时,一个类是什么时候被加载的


1.1 类是通过什么加载的?


关于一个类什么时候开始被加载的问题,《Java虚拟机规范》中并没有进行强制约束,而是交给了虚拟机自己去自由实现。


1.2 有哪几种虚拟机?


1)Sun公司最早的 Classic虚拟机;


2)Sun/Oracle公司的HotSpot虚拟机;


3)BEA公司的JRockit虚拟机;


4)IBM公司的IBM J9虚拟机。


1.3.虚拟机是怎么工作的?


Java常用的虚拟机是HotSpot虚拟机,HotSpot虚拟机是按需加载(用什么类,加载什么类),在需要用到该类时会自动加载这个类。


ps:虚拟机加载类时,是按需加载,首先会加载rt.jar 包下的类,也就是 java.lang包下的类,也就是核心基础类库,然后加载main方法中所需要的类


2、JVM 一个类的加载过程


2.1 JVM一个类的加载分为几个阶段


一个类从加载到jvm内存,到从jvm内存卸载,它的整个生命周期会经历7个阶段:


1)加载(Loading)


2)验证(Verification)


3)准备(Preparation)


4)解析(Resolution)


5)初始化(Initialization)


6)使用(Using)


7)卸载(Unloading)


2.2 他们之间的关系是怎样的?

1111.png

其中验证、准备、解析三个阶段统称为连接(Linking);




2.3 每个阶段是做什么工作的?


加载:classpath、jar包、网络、某个磁盘位置下的类的class二进制字节流读进来,在内存中生成一个代表这个类的java.lang.Class对象放入元空间,此阶段我们程序员可以干预,我们可以自定义类加载器来实现类的加载;


验证:验证Class文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证虚拟机的安全;


准备:类变量赋默认初始值,int为0,long为0L,boolean为false,引用类型为null;常量赋正式值;


解析:把符号引用翻译为直接引用;


初始化:当我们new一个类的对象,访问一个类的静态属性,修改一个类的静态属性,调用一个类的静态方法,用反射API对一个类进行调用,初始化当前类,其父类也会被初始化… 那么这些都会触发类的初始化;


使用:使用这个类;


卸载:


1.该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例;


2.加载该类的ClassLoader已经被GC;


3.该类的java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法。


3、类被初始化的过程


1.介绍类加载的过程


2.类的初始化阶段,Java虚拟机才真正开始执行类中编写的Java程序代码。


准备阶段时,变量已经赋过一次系统要求的初始零值(默认值),而在初始化阶段,才真正初始化类变量和其他资源。


继承时父子类的初始化顺序是怎样的?


父类–静态变量


父类–静态初始化块


子类–静态变量


子类–静态初始化块


父类–变量


父类–初始化块


父类–构造器


子类–变量


子类–初始化块


子类–构造器


4、JVM中不同的类加载器加载哪些文件


1.启动类加载器(Bootstrap ClassLoader):(根的类加载器)C++语言实现的


<JAVA_HOME>\jre\lib\rt.jar,resources.jar、charsets.jar被-Xbootclasspath参数所指定的路径中存放的类库;


2、扩展类加载器(Extension ClassLoader):


<JAVA_HOME>\jre\lib\ext,被java.ext.dirs系统变量所指定的路径中所有的类库;


3、应用程序类加载器(Application ClassLoader):系统的类加载器


AppClassLoader,加载用户类路径(ClassPath)上所有的类库。


5、如何自定义自己的类加载器


1)继承ClassLoader


2)覆盖findClass(String name)方法 或者 loadClass() 方法;


findClass(String name)和loadClass() 方法有什么不同?


findClass(String name)方法:不会打破双亲委派;


loadClass() 方法:可以打破双亲委派。


6、了解Tomcat 的类加载机制吗

1.png


Tomcat自定义了WebAppClassLoader类加载器,打破了双亲委派的机制,即如果收到类加载的请求,首先会尝试自己去加载,如果找不到再交给父加载器去加载,目的就是为了优先加载Web应用自己定义的类。


为什么Tomcat要破坏双亲委派模型?


Tomcat是web容器,那么一个web容器可能需要部署多个应用程序。


1、部署在同一个Tomcat上的两个Web应用所使用的Java类库要相互隔离;


2、部署在同一个Tomcat上的两个Web应用所使用的Java类库要互相共享;


3、保证Tomcat服务器自身的安全,不受部署的Web应用程序影响;


4、需要支持JSP页面的热部署和热加载。


7、ClassLoader中的loadClass()、findClass()、defineClass()的区别


loadClass():


主要进行类加载的方法,默认的双亲委派机制就实现在这个方法中.

当我们想自定义一个类加载器并且想破坏双亲委派模型时,我们会重写loadClass()方法。

findClass():


根据名称或位置加载.class字节码。

如果你想定义一个自己的类加载器,并且要遵守双亲委派模型,那么可以继承ClassLoader,并且覆盖findClass()

defineClass()


把字节码转化java.lang.Class。


8、JVM中对象如何在堆内存分配


1、指针碰撞(Bump The Pointer):内存规整的情况下;


2、空闲列表(Free List)


3、本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)


相关文章
|
14天前
|
SQL 缓存 监控
大厂面试高频:4 大性能优化策略(数据库、SQL、JVM等)
本文详细解析了数据库、缓存、异步处理和Web性能优化四大策略,系统性能优化必知必备,大厂面试高频。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:4 大性能优化策略(数据库、SQL、JVM等)
|
14天前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。
|
1月前
|
存储 监控 算法
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程 ?
尼恩提示: G1垃圾回收 原理非常重要, 是面试的重点, 大家一定要好好掌握
美团面试:说说 G1垃圾回收 底层原理?说说你 JVM 调优的过程  ?
|
1月前
|
存储 SQL 小程序
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
这篇文章详细介绍了Java虚拟机(JVM)的运行时数据区域和JVM指令集,包括程序计数器、虚拟机栈、本地方法栈、直接内存、方法区和堆,以及栈帧的组成部分和执行流程。
33 2
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
|
6天前
|
监控 算法 Java
深入理解Java虚拟机(JVM)的垃圾回收机制
【10月更文挑战第21天】 本文将带你深入了解Java虚拟机(JVM)的垃圾回收机制,包括它的工作原理、常见的垃圾收集算法以及如何优化JVM垃圾回收性能。通过本文,你将对JVM垃圾回收有一个全新的认识,并学会如何在实际开发中进行有效的调优。
24 0
|
30天前
|
存储 算法 Java
Java虚拟机(JVM)的内存管理与性能优化
本文深入探讨了Java虚拟机(JVM)的内存管理机制,包括堆、栈、方法区等关键区域的功能与作用。通过分析垃圾回收算法和调优策略,旨在帮助开发者理解如何有效提升Java应用的性能。文章采用通俗易懂的语言,结合具体实例,使读者能够轻松掌握复杂的内存管理概念,并应用于实际开发中。
|
1月前
|
Java 应用服务中间件 程序员
JVM知识体系学习八:OOM的案例(承接上篇博文,可以作为面试中的案例)
这篇文章通过多个案例深入探讨了Java虚拟机(JVM)中的内存溢出问题,涵盖了堆内存、方法区、直接内存和栈内存溢出的原因、诊断方法和解决方案,并讨论了不同JDK版本垃圾回收器的变化。
31 4
|
1月前
|
存储 算法 Java
深入理解Java虚拟机(JVM)及其优化策略
【10月更文挑战第10天】深入理解Java虚拟机(JVM)及其优化策略
43 1
|
1月前
|
安全 Java API
🌟探索Java宇宙:深入理解Java技术体系与JVM的奥秘
本文深入探讨了Java技术体系的全貌,从Java语言的概述到其优点,再到Java技术体系的构成,以及JVM的角色。旨在帮助Java开发者全面了解Java生态,提升对Java技术的认知,从而在编程实践中更好地发挥Java的优势。关键词:Java, JVM, 技术体系, 编程语言, 跨平台, 内存管理。
40 2
|
1月前
|
小程序 Oracle Java
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
这篇文章是关于JVM基础知识的介绍,包括JVM的跨平台和跨语言特性、Class文件格式的详细解析,以及如何使用javap和jclasslib工具来分析Class文件。
47 0
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
下一篇
无影云桌面