Java面试题 - JVM相关(上)

简介: Java面试题 - JVM相关
01 JVM结构

PC寄存器:

  1. 每个线程拥有⼀个pc寄存器;
  2. 指向下⼀条指令的地址。

⽅法区:

  1. 保存装载的类的元信息:类型的常量池,字段、⽅法信息,⽅法字节码;jdk6时,String等常量信息置于⽅法区,jdk7移到了堆中;
  2. 通常和永久区(Perm)关联在⼀起;

堆:

  1. 应⽤系统对象都保存在java堆中;
  2. 所有线程共享java堆;
  3. 对分代GC来说,堆也是分代的;

栈:

  1. 线程私有;
  2. 栈由⼀系列帧组成(因此java栈也叫做帧栈);
  3. 帧保存⼀个⽅法的局部变量(局部变量表)、操作数栈、常量池指针;

每⼀次⽅法调⽤创建⼀个帧,并压栈。

02 JVM内存模型
  1. 每⼀个线程有⼀个⼯作内存,和主存独⽴;
  2. ⼯作内存存放主存中变量的值的拷⻉;
  3. 对于普通变量,⼀个线程中更新的值,不能⻢上反应在其他变量中;如果需要在其他线程中⽴即可⻅,需要使⽤volatile关键字;
  4. volatile不能代替锁,⼀般认为volatile⽐锁性能好(不绝对),使⽤volatile的条件是语义是否满⾜应⽤;
  5. 可⻅性:⼀个线程修改了变量,其他线程可以⽴即知道。
  • ------------ volatile;
  • ------------ synchronized(unlock之前,写变量值回主存);
  • ------------ final(⼀旦初始化完成,其他线程可⻅)。
03 java四引⽤
  • 强引⽤:强引⽤是使⽤最普遍的引⽤。如果⼀个对象具有强引⽤,那垃圾回收器绝不会回收它。当内存空间不⾜,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终⽌,也不会靠随意回收具有强引⽤的对象来解决内存不⾜的问题。
  • 软引⽤:如果内存空间不⾜了,就会回收这些对象的内存。只要垃圾回收器没有回收它,软引⽤可以和⼀个引⽤队列(ReferenceQueue)联合使⽤,如果软引⽤所引⽤的对象被垃圾回收器回收,Java虚拟机就会把这个软引⽤加⼊到与之关联的引⽤队列中。
  • 弱引⽤:弱引⽤与软引⽤的区别在于:只具有弱引⽤的对象拥有更短暂的⽣命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,⼀旦发现了只具有弱引⽤的对象,不管当前内存空间⾜够与否,都会回收它的内存。弱引⽤可以和⼀个引⽤队列(ReferenceQueue)联合使⽤,如果弱引⽤所引⽤的对象被垃圾回收,Java虚拟机就会把这个弱引⽤加⼊到与之关联的引⽤队列中。
  • 虚引⽤:虚引⽤在任何时候都可能被垃圾回收器回收,主要⽤来跟踪对象被垃圾回收器回收的活动,被回收时会收到⼀个系统通知。虚引⽤与软引⽤和弱引⽤的⼀个区别在于:虚引⽤必须和引⽤队列 (ReferenceQueue)联合使⽤。当垃圾回收器准备回收⼀个对象时,如果发现它还有虚引⽤,就会在回收对象的内存之前,把这个虚引⽤加⼊到与之关联的引⽤队列中。
04 GC算法分类

引⽤计数法(没有被java采⽤):

  • 原理:对于⼀个对象A,只要有任何⼀个对象引⽤了A,则A的引⽤计数器就加1,当引⽤失效时,引⽤计数器就减1,只要对象A的引⽤计数器的值为0,则对象A就会被回收。
  • 问题:引⽤和去引⽤伴随加法和减法,影响性能;很难处理循环引⽤。

标记清除法:

  • 原理:现代垃圾回收算法的思想基础。标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。⼀种可⾏的实现是,在标记节点,⾸先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引⽤的垃圾对象。然后在清除阶段,清除所有未被标记的对象。
  • 问题:标记和清除两个过程效率不⾼,产⽣内存碎⽚导致需要分配较⼤对象时⽆法找到⾜够的连续内存⽽需要触发⼀次GC操作。

标记压缩法:

  • 原理:适合⽤于存活对象较多的场合,如⽼年代。它在标记-清除算法的基础上做了⼀些优化。标记阶段⼀样,但之后,将所有存活对象压缩到内存的⼀端。之后,清除边界外所有的空间。
  • 优点: 解决了标记- 清除算法导致的内存碎⽚问题和在存活率较⾼时复制算法效率低的问题。

复制算法:

  • 原理:将原有的内存空间分为两块,每次只使⽤其中⼀块,在垃圾回收时,将正在使⽤的内存中的存活对象复制到未使⽤的内存块中,之后清除正在使⽤的内存块中的所有对象,交换两个内存的⻆⾊,完成垃圾回收。
  • 问题: 不适⽤于存活对象⽐较多的场合,如⽼年代。

分代回收法:

  • 原理:根据对象存活周期的不同将内存划分为⼏块,⼀般是新⽣代和⽼年代,新⽣代基本采⽤复制算法,⽼年代采⽤标记整理算法。
05 MinorGC & FullGC
  1. Minor GC通常发⽣在新⽣代的Eden区,在这个区的对象⽣存期短,往往发⽣GC的频率较⾼,回收速度⽐较快,⼀般采⽤复制-回收算法。
  2. Full GC/Major GC 发⽣在⽼年代,⼀般情况下,触发⽼年代GC的时候不会触发Minor GC,所采⽤的是标记-清除算法。
06 垃圾收集器
  1. Serial New收集器是针对新⽣代的收集器,采⽤的是复制算法;
  2. Parallel New(并⾏)收集器,新⽣代采⽤复制算法,⽼年代采⽤标记整理;
  3. Parallel Scavenge(并⾏)收集器,针对新⽣代,采⽤复制收集算法;
  4. Serial Old(串⾏)收集器,新⽣代采⽤复制,⽼年代采⽤标记清理;
  5. Parallel Old(并⾏)收集器,针对⽼年代,标记整理;
  6. CMS收集器,基于标记清理;
  7. G1收集器(JDK):整体上是基于标记清理,局部采⽤复制;

综上:新⽣代基本采⽤复制算法,⽼年代采⽤标记整理算法,cms采⽤标记清理;

07 Java类加载机制

概念:

  • 虚拟机把描述类的数据⽂件(字节码)加载到内存,并对数据进⾏验证、准备、解析以及类初始化,最终形成可以被虚拟机直接使⽤的java类型(java.lang.Class对象)。

类⽣命周期:

  • 类加载过程:读取⼆进制字节流到jvm—>验证格式语义等—>为静态变量分配内存空间—>常量池引⽤解析—>执⾏static标识的代码。
  1. 加载过程:通过⼀个类的全限定名来获取定义此类的⼆进制字节流,将这个字节流所代表的静态存储结构转化为⽅法区的运⾏时数据结构。在内存中(⽅法区)⽣成⼀个代表这个类的java.lang.Class对象,作为⽅法区这个类的各种数据的访问⼊⼝;
  2. 验证过程:为了确保Class⽂件的字节流中包含的信息符合当前虚拟机的要求,⽂件格式验证、元数据验证、字节码验证、符号引⽤验证;
  3. 准备过程:正式为类属性分配内存并设置类属性初始值的阶段,这些内存都将在⽅法区中进⾏分配;

准备阶段,static对象会被设置默认值,static final对象会被赋上给予的值。

  1. 解析阶段:虚拟机将常量池内的符号引⽤替换为直接引⽤的过程。

i. 符号引⽤:字符串,引⽤对象不⼀定被加载;

ii. 直接引⽤:指针或者地址偏移量,引⽤对象⼀定在内存中。

  1. 初始化阶段:类初始化阶段是类加载过程的最后⼀步。初始化阶段就是执⾏类构造<clint>()⽅法的过程。
  2. 使⽤阶段:
  3. 卸载阶段:
08 类加载器

java默认提供三个类加载器:

  1. BootStrap ClassLoader 启动ClassLoader(sun.boot.class.path):最顶层的加载类,主要加载jdk中的核⼼库,%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。BootstrapClassLoader不继承⾃ClassLoader,因为它不是⼀个普通的Java类,底层由C++编写,已嵌⼊到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核⼼类库后,并构造Extension ClassLoader和App ClassLoader类加载器。
  2. Extension ClassLoader 扩展ClassLoader(java.ext.dirs):扩展的类加载器,加载⽬录%JRE_HOME%\lib\ext⽬录下的jar包和class⽂件。还可以加载-D java.ext.dirs选项指定的⽬录。
  3. App ClassLoader 应⽤ClassLoader/系统ClassLoader(java.class.path):也称为SystemAppClass加载当前应⽤的classpath的所有类。 除了BootStrap ClassLoader,每个ClassLoader都有⼀个Parent作为⽗亲。

双亲委派机制:

  1. 定义:当⼀个ClassLoader实例需要加载某个类时,它会试图亲⾃搜索某个类之前,先把这个任务委托给它的⽗类加载器,这个过程是由上⾄下依次检查的,⾸先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没加载到,则把任务转交给Extension ClassLoader试图加载,如果也没加载到,则转交给App ClassLoader 进⾏加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的⽂件系统或⽹络等URL中加载该类。如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。否则将这个找到的类⽣成⼀个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。
  2. 作⽤:避免重复加载;考虑到安全因素,避免⾃定义的类去替代系统类,如String。
  3. jvm如何判定两个class是否相同?JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,⽽且要判断是否由同⼀个类加载器实例加载的。只有两者同时满⾜的情况下,JVM才认为这两个class是相同的。
  1. ⾃底向上检查类是否已经加载;
  2. ⾃顶向下尝试加载类。

custom classloader:⾃定义classloader

a. Java中提供的默认ClassLoader,只加载指定⽬录下的jar和class,如果我们想加载其它位置的类或jar时,就需要定义⾃⼰的ClassLoader。

b. 步骤:

  1. 继承java.lang.ClassLoader
  2. 重写⽗类的findClass⽅法
09 引起类加载的五个⾏为
  1. 遇到new、getstatic、putstatic或invokestatic这四条字节码指令
  2. 反射调⽤的时候,如果类没有进⾏过初始化,则需要先触发其初始化
  3. ⼦类初始化的时候,如果其⽗类还没初始化,则需先触发其⽗类的初始化
  4. 虚拟机执⾏主类的时候(有 main(string[] args))
  5. JDK1.7 动态语⾔⽀持
目录
相关文章
|
29天前
|
监控 算法 Java
Java虚拟机(JVM)的垃圾回收机制深度解析####
本文深入探讨了Java虚拟机(JVM)的垃圾回收机制,旨在揭示其背后的工作原理与优化策略。我们将从垃圾回收的基本概念入手,逐步剖析标记-清除、复制算法、标记-整理等主流垃圾回收算法的原理与实现细节。通过对比不同算法的优缺点及适用场景,为开发者提供优化Java应用性能与内存管理的实践指南。 ####
|
21天前
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
26 0
|
24天前
|
Java 程序员
Java社招面试题:& 和 && 的区别,HR的套路险些让我翻车!
小米,29岁程序员,分享了一次面试经历,详细解析了Java中&和&&的区别及应用场景,展示了扎实的基础知识和良好的应变能力,最终成功获得Offer。
62 14
|
1月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
18天前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
20天前
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
24天前
|
机器学习/深度学习 监控 算法
Java虚拟机(JVM)的垃圾回收机制深度剖析####
本文深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法、性能调优策略及未来趋势。通过实例解析,为开发者提供优化Java应用性能的思路与方法。 ####
34 1
|
28天前
|
Java 编译器 程序员
Java面试高频题:用最优解法算出2乘以8!
本文探讨了面试中一个看似简单的数学问题——如何高效计算2×8。从直接使用乘法、位运算优化、编译器优化、加法实现到大整数场景下的处理,全面解析了不同方法的原理和适用场景,帮助读者深入理解计算效率优化的重要性。
32 6
|
24天前
|
Oracle 安全 Java
深入理解Java生态:JDK与JVM的区分与协作
Java作为一种广泛使用的编程语言,其生态中有两个核心组件:JDK(Java Development Kit)和JVM(Java Virtual Machine)。本文将深入探讨这两个组件的区别、联系以及它们在Java开发和运行中的作用。
56 1
|
1月前
|
监控 Java 开发者
Java虚拟机(JVM)深度优化指南####
本文深入探讨了Java虚拟机(JVM)的工作原理及其性能优化策略,旨在帮助开发者通过理解JVM的内部机制来提升Java应用的运行效率。不同于传统的技术教程,本文采用案例分析与实战技巧相结合的方式,为读者揭示JVM调优的艺术。 ####
58 8