快速了解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)


相关文章
|
7天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
25 2
|
12天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
17天前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
Java I/O流面试之道
|
14天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
39 4
|
15天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
55 4
|
27天前
|
存储 Java 程序员
Java面试加分点!一文读懂HashMap底层实现与扩容机制
本文详细解析了Java中经典的HashMap数据结构,包括其底层实现、扩容机制、put和查找过程、哈希函数以及JDK 1.7与1.8的差异。通过数组、链表和红黑树的组合,HashMap实现了高效的键值对存储与检索。文章还介绍了HashMap在不同版本中的优化,帮助读者更好地理解和应用这一重要工具。
54 5
|
26天前
|
存储 Java
[Java]面试官:你对异常处理了解多少,例如,finally中可以有return吗?
本文介绍了Java中`try...catch...finally`语句的使用细节及返回值问题,并探讨了JDK1.7引入的`try...with...resources`新特性,强调了异常处理机制及资源自动关闭的优势。
20 1
|
27天前
|
存储 算法 Java
Java虚拟机(JVM)的内存管理与性能优化
本文深入探讨了Java虚拟机(JVM)的内存管理机制,包括堆、栈、方法区等关键区域的功能与作用。通过分析垃圾回收算法和调优策略,旨在帮助开发者理解如何有效提升Java应用的性能。文章采用通俗易懂的语言,结合具体实例,使读者能够轻松掌握复杂的内存管理概念,并应用于实际开发中。
|
1月前
|
Java 程序员
Java 面试高频考点:static 和 final 深度剖析
本文介绍了 Java 中的 `static` 和 `final` 关键字。`static` 修饰的属性和方法属于类而非对象,所有实例共享;`final` 用于变量、方法和类,确保其不可修改或继承。两者结合可用于定义常量。文章通过具体示例详细解析了它们的用法和应用场景。
28 3
|
25天前
|
算法 Java
JAVA 二叉树面试题
JAVA 二叉树面试题
14 0

热门文章

最新文章

下一篇
无影云桌面