【Java面试课程】JVM

本文详细介绍了JVM内存区域划分,包括程序计数器、Java虚拟机栈、堆、方法区、运行时常量池及本地方法栈,探讨了OutOfMemoryError的原因。同时,深入解析了垃圾收集器如Serial、ParNew、Parallel、CMS和G1的工作原理,以及对象回收判断和常见垃圾收集算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.谈谈JVM内存区域的划分,哪些区域可能发生OutOfMemoryError?

典型回答

通常可以把内存分为下面几个区域。其中有的区域是以线程为单位的,而有的区域是整个JVM进程唯一的。


首先,程序计数器。在JVM规范中,每个线程都有它自己的程序计数器,并且任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法。程序计数器会指定当前线程正在执行的Java方法的JVM指令地址。或者如果是执行虚拟机本地方法,则是未指定值。


第二。Java虚拟机栈。早期也叫Java栈。每个线程在创建的时候都会创建一个虚拟机栈,其内部保存一个个的栈帧,对应一次次的Java方法调用。

在一个时间点,只能有一个活动的栈帧,通常称为当前帧,方法所在的类称为当前类。如果在该方法中调用了其它方法,对应的新的栈帧会被创建出来,成为一个新的当前帧,一直到它返回当前结果或执行结束。JVM对Java栈的操作只有两个,就是对栈帧的压栈和出栈。

栈帧中保存局部变量、操作数栈、动态链接等


第三 堆(Heap),它是Java内存管理的核心区域,用来放置Java对象实例,几乎所有创建的Java对象都是被直接分配到堆上。堆被所有的线程共享。

理所当然,堆也是垃圾回收器重点照顾的区域。所以堆内空间还会被不同的垃圾回收器进一步细分,最著名的有新生代、老年代的划分


第四 方法区 这也是所有线程共享的一块内存区域,用来存储所谓的元数据。例如类结构信息,以及对应的运行时常量池、字段、方法代码等


第五 运行时常量池 方法区的一部分。Java的常量池可以存放各种常量信息,不管是编译期生成的各种字面量,还是需要在运行时决定的符号引用。


第六 本地方法栈 与Java虚拟机栈类似,支持对本地方法调用,也是每个线程都会创建一个
在这里插入图片描述

OOM原因分析

首先,OOM 如果通俗点儿说,就是 JVM 内存不够用了。没有空闲内存,而且垃圾回收器也无法提供更多内存。

隐含的意思是在抛出OutOfMemoryError之前,通常垃圾回收器会被触发,尽其所能去清理出空间。

当然也不是在任何情况下垃圾回收器都会触发。比如我们分配一个超大对象,类似一个超大数组超过堆的最大值,JVM会判断垃圾回收并不能解决这个问题,所以直接抛出OutOfMemoryError。

除了程序计数器,其他区域都有可能会因为可能的空间不足产生OutOfMemoryError。总结如下:

  • 堆内存不足是常见的OOM原因之一OutOfMemoryError:Java heap space原因有很多,比如内存泄漏、堆大小设置不足、JVM处理不及时、内存无法释放
  • Java 虚拟机栈和本地方法栈。比如写一段递归没有跳出条件。会不断压栈。导致StackOverFlowError

2. Java常见的垃圾收集器有哪些?

垃圾收集机制是 Java 的招牌能力,极大地提高了开发效率。
Java 的垃圾收集机制仍然在不断的演进中,不同大小的设备、不同特征的应用场景、对垃圾收集提出了新的挑战

典型回答

实际上,垃圾收集器(GC,Garbage Collector)是和具体JVM实现紧密相关的。不同厂商、不同版本的JVM提供的选择也不同。

我们这里讨论的是最主流的Oracle JDK

  • Serial GC,新生代,最古老的垃圾收集器。Serial体现在收集工作是单线程的,并且在进行垃圾收集过程中,会进入臭名昭著的"Stop the world"。当然其单线程设计也意味着精简的GC实现,无需维护复杂的数据结构,初始化也简单。
  • ParNew GC 新生代GC实现。它实际上是Serial GC的多线程版本。最常见的应用场景是配合老年代的CMS GC工作
  • Parrallel GC。新生代收集器、也是使用复制算法、也是并行的多线程收集器。与ParNew GC的区别在于Parrallel GC目标在于得到一个可控制的吞吐量,也称为吞吐量优先
  • CMS(Concurrent Mark Sweep) GC,基于标记-清除(Mark Sweep)算法。设计目标是尽量减少停顿时间。这对于Web等反应时间敏感的应用非常重要。但是CMS算法采用的标记-清除(Mark Sweep)算法,存在着内存碎片化问题,难以避免长时间使用的情况下出现full GC,导致恶劣的停顿。另外既然强调了并发(Concurrent),CMS会占用更多CPU资源,并和用户线程争抢
  • G1 GC。这是一种兼顾吞吐量和停顿时间的GC实现,G1可以直观的设定停顿时间的目标。相比于CMS GC,G1未必能做到CMS在最好情况下的延时停顿,但是最差情况要好很多。G1 GC中仍然存在年代的概念,但是内存结构类似于棋盘的region。region之间是复制算法。但整体上可以看做为标记-整理(Mark-Compact)算法,有效避免内存碎片

3.在JVM GC中如何判断一个对象是否可以回收?

主要有两种算法:引用计数和可达性分析

  • 引用计数算法。顾名思义,为对象添加一个引用计数,用于记录对象被引用的情况。每当有一个地方引用它,计数器加1.引用失效,计数器-1。如果计数为0则表示对象可回收。优点:简单高效 缺点: 很难解决对象之间相互循环引用的问题。
  • 可达性分析。通过一系列的称为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链。如果一个对象到GC Roots没有任何引用链(图论的角度表示为不可达),则该对象可回收

4.常见的垃圾收集算法

主要分为三种算法

  • 标记-清除(Mark-Sweep)算法 首先进行标记工作,标识出所有要回收的对象,标记完成后统一进行清除。缺点有效率低,标记完成后会产生大量的内存碎片。空间内存太多可能会导致下一次分配较大对象时没有连续内存。
  • 复制算法 将可用的内存容量分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存一次性清理掉。这样每次只对一个半区进行内存回收,内存分配时不用考虑内存碎片等问题。代价是只使用一半的内存空间。
  • 现在大部分的新生代GC都是基于复制算法。新生代大部分的对象都是朝生夕死的。将内存分为一块较大的Eden区和两块较小的Survivor区域。每次使用Eden和一个Survivor.每次清理时把Eden和Survivor中还活着的区域复制到另外一块Survivor,最后清理掉刚才使用的Eden和Survivor区域。
  • 标记-整理(Mark-Compact)算法 类似于标记-清除(Mark-Sweep)算法,但为了避免内存碎片化,它会在清理过程中将对象移动,以确保移动后的对象占用连续的内存空间

5. 垃圾收集过程

垃圾收集过程取决于具体的GC方式。先来熟悉一下通常的垃圾回收过程。

第一步:Java应该不断创建对象,通常都是分配在Eden区域,当空间占用一定阈值时,触发Minor GC.。仍然被引用的对象(绿色方块)存活下来,被复制到 JVM 选择的 Survivor 区域,而没有被引用的对象(黄色方块)则被回收。注意,我给存活对象标记了“数字 1”,这是为了表明对象的生存时间
在这里插入图片描述
第二, 经过一次 Minor GC,Eden 就会空闲下来,直到再次达到 Minor GC 触发条件,这时候,另外一个Survivor 区域则会成为 to 区域,Eden 区域的存活对象和 From 区域对象,都会被复制到 to 区域,并且存活的年龄计数会被加 1
在这里插入图片描述
第三, 类似第二步的过程会发生很多次,直到有对象年龄计数达到阈值,这时候就会发生所谓的晋升(Promotion)过程,如下图所示,超过阈值的对象会被晋升到老年代。
在这里插入图片描述
后面就是老年代 GC,具体取决于选择的 GC 选项,对应不同的算法。下面是一个简单标记 - 整理算法过程示意图,老年代中无用对象被清除后, GC 会将对象进行整理,以防止内存碎片化
在这里插入图片描述
通常我们把老年代 GC 叫作 Major GC,将对整个堆进进行的清理叫作 Full GC

6. 强引用、软引用、弱引用、幻象引用有什么区别?

在 Java 语言中,除了原始数据类型的变量,其他所有都是所谓的引用类型,指向各种不同的对象,理解引用对于掌握 Java对象生命周期和 JVM 内部相关机制非常有帮助。

典型回答

不同的引用类型,主要体现的是对象不同的可达性(reachable)状态和对垃圾收集的影响。

强引用(“Strong” Reference),就是我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表明对象还“活着”,垃圾收集器不会碰这种对象。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,当然具体回收时机还是要看垃圾收集策略

软引用(SoftReference),是一种相对强引用弱化一些的引用,可以让对象豁免一些垃圾收集,只有当 JVM 认为内存不足时,才会去试图回收软引用指向的对象。JVM 会确保在抛出 OutOfMemoryError 之前,清理软引用指向的对象。软引用通常用来实现内存敏感的缓存,如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉。

弱引用(WeakReference)并不能使对象豁免垃圾收集,仅仅是提供一种访问在弱引用状态下对象的途径。这就可以用来构建一种没有特定约束的关系,比如,维护一种非强制性的映射关系,如果试图获取时对象还在,就使用它,否则重现实例化。它同样是很多缓存属性实现的选择。

幻象引用,有时候也翻译成虚引用,你不能通过它访问对象。幻象引用仅仅是提供了一种确保对象被 finalize 以后,

这道面试题,属于既偏门又非常高频的一道题目。说它偏门,是因为在大多数应用开发中,很少直接操作各种不同引用,虽然我们使用的类库、框架可能利用了其机制。它被频繁问到,是因为这是一个综合性的题目,既考察了我们对基础概念的理解,也考察了对底层对象生命周期、垃圾收集机制等的掌握。

对象可达性状态流转

这里简单总结了对象生命周期和不同可达性状态,以及不同状态可能的改变关系。
在这里插入图片描述
这是 Java 定义的不同可达性级别(reachabilitity level)

强可达(Strongly Reachable),就是当一个对象可以有一个或多个线程可以不通过各种引用访问到的情况。比如,我们新创建一个对象,那么创建它的线程对他就是强可达。

软可达(Softly Reachable),就是当我们只能通过软引用才能访问到对象的状态。

弱可达(Weakly Reachable),无法通过强引用或者软引用访问,只能通过弱引用访问时的状态。这是十分临近 finalize 状态的时机,当弱引用被清除的时候,就符合 finalize 的条件了。

幻象可达(Phantom Reachable)没有强、软、弱引用关联,并且 finalize 过了,只有幻象引用指向这个对象的时候。

最后的状态,就是不可达(unreachable),意味着对象可以被清除了。

7. 介绍类加载过程?什么是双亲委派模型?

Java 通过引入字节码和 JVM 机制,提供了强大的跨平台能力,理解 Java 的类加载机制是深入 Java 开发的必要条件,也是个面试考察热点

典型回答

一般来说,我们把Java的类加载过程分为三个主要步骤:加载、链接、初始化。

首先是加载阶段,它是Java把字节码数据从不同的数据源读取到JVM中,并映射为JVM认可的数据机构(Class对象)

加载阶段是用户参与的阶段,我们可以自定义类加载器,去实现自己的类加载过程。

第二阶段是链接,这是核心的步骤,简单来说把原始的类定义信息平滑地转入JVM运行的过程中。这里可以细分为三个步骤:

  • 验证,虚拟机安全的重要保障,JVM需要核验字节信息是符合Java虚拟机规范的。防止恶意信息
  • 准备,创建类或接口中的静态变量,并初始化静态变量的初始值。重点在于分配所需要的内存空间。
  • 解析,在这一步会将常量池中的符号引用替换为直接引用。

最后是初始化阶段,这一步真正去执行类初始化的代码逻辑,包括静态字段赋值的动作,以及执行类定义中的静态初始化块的逻辑。

双亲委派模型,简单说就是类加载器试图加载某个类型的时候,除非父加载器找不到相应类型,否则尽量将这个任务代理给当前加载器的父加载器去做。使用委派模型的目的是避免重复加载Java类型。

面试题包含了不同技术层面的面试问题,同时也能对一些没有面试开发经验的小白给予不可估量的包装, 让你的薪水绝对翻倍, 本人亲试有效.Java面试题84集、java面试专属及面试必问课程,所有的面试题有视屏讲解, 解答方案.以下是部分目录: java面试题01.面试的整体流程.mp4 │ Java面试题02.java的垮平台原理.mp4 │ Java面试题03.搭建一个java的开发环境.mp4 │ Java面试题04.java中int占几个字节.mp4 │ Java面试题05.java面向对象的特征.mp4 │ Java面试题06.装箱和拆箱.mp4 │ Java面试题07.==和equals的区别.mp4 │ Java面试题08.String.mp4 │ Java面试题09.讲一下java中的集合.mp4 │ Java面试题10.ArrayList LinkedList.mp4 │ Java面试题11.HashMap和HashTable的区别.mp4 │ Java面试题12.实现一个拷贝文件的类使用字节流还是字符串.mp4 │ Java面试题13.线程的实现方式 怎么启动线程怎么区分线程.mp4 │ Java面试题14.线程并发库和线程池的作用?.mp4 │ Java面试题15.设计模式和常用的设计模式.mp4 │ Java面试题16.http get post请求的区别.mp4 │ Java面试题17.说说你对Servlet的理解.mp4 │ Java面试题18.Servlet的生命周期.mp4 │ Java面试题19.forward和redirect的区别.mp4 │ Java面试题20.jsp和Servlet的相同点和不同点?.mp4 │ Java面试题21.内置对象和四大作用域和页面传值.mp4 │ Java面试题22.Session和Cookie的区别.mp4 │ Java面试题23.mvc模式和mvc各部分的实现.mp4 │ Java面试题24.数据库分类和常用数据库.mp4 │ Java面试题25.关系型数据库的三范式.mp4 │ Java面试题26.事务的四大特征.mp4 │ Java面试题27.mysql数据库最大连接数.mp4 │ Java面试题28.mysql和oracle的分页语句(着重说思路).mp4 │ Java面试题29.触发器的使用场景.mp4 │ Java面试题30.存储过程的优点.mp4 │ Java面试题31.jdbc调用存储过程.mp4 │ Java面试题32.简单说一下你对jdbc的理解.mp4 │ Java面试题33.写一个jdbc的访问oracle的列子.mp4 │ Java面试题34.jdbc中preparedStatement比Statement的好处.mp4 │ Java面试题35.数据库连接池的作用.mp4 │ Java面试题36.HTML.mp4 │ Java面试题37.简单介绍了一下Ajax.mp4 │ Java面试题38.js和JQuery的关系.mp4 │ Java面试题39.jQuery中的常用选择器.mp4 │ Java面试题40.jQuery中页面加载完毕事件.mp4 │ Java面试题41.jQuery中Ajax和原生js实现Ajax的关系.mp4 │ Java面试题42.简单说一下html5.mp4 │ Java面试题43.简单说一下css3.mp4 │ Java面试题44.bootstrap的是什么.mp4 │ Java面试题45.什么是框架.mp4 │ Java面试题46.简单介绍一下MVC模式.mp4 │ Java面试题47.简单说一下对mvc框架的理解.mp4 │ Java面试题48.struts2的执行流程或者struts2的原理.mp4 │ Java面试题49.Struts2的拦截器是什么?你都用它干什么?.mp4 │ Java面试题50.Spring MVC的执行流程.mp4 │ Java面试题51.SpringMVC和Struts2的不同.mp4 │ Java面试题52.简单介绍一下Spring或者Spring的两大核心.mp4 │ Java面试题53.AOP是什么?都用它做什么?.mp4 │ Java面试题54.Spring事务的传播特性和隔离级别.mp4 │ Java面试题55.ORM是什么?ORM框架是什么?.mp4 │ Java面试题56.ibatis和hibernate有什么不同.mp4 │ Java面试题57.hibernate对象状态及其转换.mp4 │ Java面试题58:hibernate的缓存.mp4 │ Java面试题59.webservice的使用场景.mp4 │ Java面试题60.Activiti的简单介绍.mp4 │ Java面试题61.linux的使用场景.mp4 │ Java面试题62.linux常用命令.mp4 │ Java面试题63:怎么操作linux服务器.mp4 │ Java面试题64:有没有使用过云主机.mp4 │ Java面试题65:数据库优化方面的事情.mp4 │ Java面试题66:如果查询和定位慢查询.mp4 │ Java面试题67:数据库优化之数据库表设计遵循范式.mp4 │ Java面试题68:选择合适的数据库引擎.mp4 │ Java面试题69:选择合适的索引.mp4 │ Java面试题70:使用索引的一些技巧.mp4 │ Java面试题71:数据库优化之分表.mp4 │ Java面试题72:数据库的读写分离.mp4 │ Java面试题73:数据库优化之缓存.mp4 │ Java面试题74:sql语句优化小技巧.mp4 │ Java面试题75:批量插入几百万条数据.mp4 │ Java面试题76:有没有使用过redis.mp4 │ Java面试题77:redis的使用场景.mp4 │ Java面试题78:redis存储对象的方式.mp4 │ Java面试题79:redis数据淘汰机制.mp4 │ Java面试题80:java访问redis级redis集群?.mp4 │ Java面试题81:微信公众号分类和微信开发原理.mp4 │ Java面试题82:怎么把微信和业务平台进行绑定.mp4 │ Java面试题83:项目的分类和项目参与者.mp4 │ Java面试题84:项目流程和业务注意事项.mp4 │ 面试必问-Mysql索引背后的故事 │ ├─java面试专属 │ ├─1.面试必考之HashMap源码分析与实现 │ │ 1.面试必考之HashMap源码分析与实现.mp4 │ │ │ ├─2.探索JVM底层奥秘ClassLoader源码分析与案例讲解 │ │ 2.探索JVM底层奥秘ClassLoader源码分析与案例讲解.wmv │ │ │ ├─3.锁、分布式锁、无锁实战全局性ID-悟空 │ │ 3.锁、分布式锁、无锁实战全局性ID-悟空.mp4 │ │ │ ├─4.SpringMvc深入理解源码分析 │ │ 4.SpringMvc深入理解源码分析-悟空.mp4 │ │ │ ├─5.Nosql Redis Jedis常用命令 │ │ 5.Nosql Redis Jedis常用命令-悟空.mp4 │ │ │ ├─6.互联网系统垂直架构之Session解决方案 │ │ 6.互联网系统垂直架构之Session解决方案.mp4 │ │ │ ├─7.分布式框架ZooKeeper之服务注册与订阅 │ │ 7.分布式框架Zookeeper之服务注册与订阅.mp4 │ │ │ ├─8.高性能网络编程必备技能之IO与NIO阻塞分析 │ │ 8.高性能网络编程必备技能之IO与NIO阻塞分析.mp4 │ │ │ ├─9.JAVA并发编程之多线程并发同步业务场景与解决方案 │ │ 9.JAVA并发编程之多线程并发同步业务场景与解决方案.wmv │ │ │ ├─10.微服务架构之Spring Cloud Eureka 场景分析与实战 │ │ 10.微服务架构之Spring Cloud Eureka 场景分析与实战.wmv │ │ │ ├─11.高性能必学之Mysql主从架构实践 │ │ 11.高性能必学之Mysql主从架构实践.mp4 │ │ │ ├─12.架构师不得不知道的Spring事物不能回滚的深层次原因 │ │ 12.架构师不得不知道的Spring事物不能回滚的深层次原因.mp4 │ │ │ ├─13.RPC底层通讯原理之Netty线程模型源码分析 │ │ 13.RPC底层通讯原理之Netty线程模型源码分析.wmv │ │ │ ├─14.分库分表之后分布式下如何保证ID全局唯一性 │ │ 14.分库分表之后分布式下如何保证ID全局唯一性.mp4 │ │ │ └─15.大型公司面试必答之数据结构与算法精讲 │ 大型公司面试必答之数据结构与算法(一)-达摩老师.mp4 │ 大型公司面试必答之数据结构与算法(二).mp4 │ ├─面试必问-JVM性能调优 │ JVM性能调优 2018-10-25.mp4 │ ├─面试必问-mybaits源码分析 │ │ 鲁班学院-上课笔记mybaits源码分析9-05.docx │ │ │ └─mybaits源码分析 │ mybaits源码分析.mp4 │ ├─面试必问-springcloud架构微服务项目 │ springcloud架构微服务项目.mp4 │ ├─面试必问-SpringMVC源码分析 │ SpringMVC源码分析.mp4 │ ├─面试必问-webservice原理分析 │ webservice原理分析.mp4 │ ├─面试必问-使用Springboot快速搭建SSM框架 │ 使用SpringBoot快速搭建SSM框架.mp4 │ ├─面试必问-双十一系统架构之Mysql索引技术剖析 │ 双十一系统架构之Mysql索引技术剖析.mp4 │ ├─面试必问-大牛带你手写dubbo框架 │ 大牛带你手写Dubbo框架.mp4 │ ├─面试必问-实战分布式之手写分布式事务框架 │ 实战分布式之手写分布式事务框架.mp4 │ ├─面试必问-带你精通springAOP—面试无忧虑 │ 带你精通AOP——面试无忧虑.mp4 │ ├─面试必问-微服务架构深入浅出讲解springcloud │ 微服务架构 --深入浅出讲解springcloud.mp4 │ ├─面试必问-教你手写MyBatis框架 │ 一小时教你手写MyBatis框架.mp4 │ ├─面试必问-架构杀手锏——java混乱的日志体系 │ java混亂日志体系源码揭秘.mp4 │ ├─面试必问-深入微服务之SpringBoot&Docker1 │ 深入微服务之SpringBoot&Docker.mp4 │ └─面试必问-聊聊哈希算法与HashMap
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值