Java面试题 - JVM相关(下)

简介: Java面试题 - JVM相关(下)
10 java对象创建时机
  1. 使⽤new关键字创建对象
  2. 使⽤Class类的newInstance⽅法(反射机制)
  3. 使⽤Constructor类的newInstance⽅法(反射机制)
  4. 使⽤Clone⽅法创建对象
  5. 使⽤(反)序列化机制创建对象
11 JVM调优

调优时机:

  • heap 内存(⽼年代)持续上涨达到设置的最⼤内存值;
  • Full GC 次数频繁;
  • GC 停顿时间过⻓(超过1秒);
  • 应⽤出现OutOfMemory 等内存异常;
  • 应⽤中有使⽤本地缓存且占⽤⼤量内存空间;
  • 系统吞吐量与响应性能不⾼或下降。

调优原则:

  • 多数的Java应⽤不需要在服务器上进⾏JVM优化;
  • 多数导致GC问题的Java应⽤,都不是因为我们参数设置错误,⽽是代码问题;
  • 在应⽤上线之前,先考虑将机器的JVM参数设置到最优(最适合);
  • 减少创建对象的数量;
  • 减少使⽤全局变量和⼤对象;
  • JVM优化是到最后不得已才采⽤的⼿段;
  • 在实际使⽤中,分析GC情况优化代码⽐优化JVM参数更好;

调优⽬标:

  • GC低停顿;
  • GC低频率;
  • 低内存占⽤;
  • ⾼吞吐量;

调优步骤:

  • 分析GC⽇志及dump⽂件,判断是否需要优化,确定瓶颈问题点;
  • 确定jvm调优量化⽬标;
  • 确定jvm调优参数(根据历史jvm参数来调整);
  • 调优⼀台服务器,对⽐观察调优前后的差异;
  • 不断的分析和调整,知道找到合适的jvm参数配置;
  • 找到最合适的参数,将这些参数应⽤到所有服务器,并进⾏后续跟踪。
12 jvm调优参数
  1. 设定堆内存⼤⼩,这是最基本的。
  2. -Xms:启动JVM时的堆内存空间。
  3. -Xmx:堆内存最⼤限制。
  4. 设定新⽣代⼤⼩。
  5. 新⽣代不宜太⼩,否则会有⼤量对象涌⼊⽼年代。
  6. -XX:NewRatio:新⽣代和⽼年代的占⽐。
  7. -XX:NewSize:新⽣代空间。
  8. -XX:SurvivorRatio:伊甸园空间和幸存者空间的占⽐。
  9. -XX:MaxTenuringThreshold:对象进⼊⽼年代的年龄阈值。
  10. 设定垃圾回收器
  • ----年轻代:-XX:+UseParNewGC。
  • ----⽼年代:-XX:+UseConcMarkSweepGC。
  • ----CMS可以将STW时间降到最低,但是不对内存进⾏压缩,有可能出现“并⾏模式失败”。⽐如⽼年代空间还有300MB空间,但是⼀些10MB的对象⽆法被顺序的存储。这时候会触发压缩处理,但是CMS GC模式下的压缩处理时间要⽐Parallel GC⻓很多。
  • ----G1采⽤”标记-整理“算法,解决了内存碎⽚问题,建⽴了可预测的停顿时间类型,能让使⽤者指定在⼀个⻓度为M毫秒的时间段内,消耗在垃圾收集上的时间不得超过N毫秒。
13 触发full gc的场景及应对策略
  1. System.gc()⽅法的调⽤,应对策略:通过-XX:+DisableExplicitGC来禁⽌调⽤System.gc ;
  2. ⽼年代代空间不⾜,应对策略:让对象在Minor GC阶段被回收,让对象在新⽣代多存活⼀段时间,不要创建过⼤的对象及数组;
  3. 永⽣区空间不⾜,应对策略:增⼤PermGen空间;
  4. GC时出现promotionfailed和concurrent mode failure,应对策略:增⼤survivor space;
  5. Minor GC后晋升到旧⽣代的对象⼤⼩⼤于⽼年代的剩余空间,应对策略:增⼤Tenured space 或下CMSInitiatingOccupancyFraction=60;
  6. 内存持续增涨达到上限导致Full GC,应对策略:通过dumpheap 分析是否存在内存泄漏。
14 jvm堆的基本结构

  1. JVM中堆空间可以分成三个⼤区,新⽣代、⽼年代、永久代
  2. 新⽣代可以划分为三个区,Eden区,两个Survivor区,在HotSpot虚拟机Eden和Survivor的⼤⼩⽐例为8:1
15 如何查看jvm内存使⽤情况

可以使⽤JDK⾃带的JConsole、JVisualVM、JMap、JHat等⼯具,或者使⽤第三⽅⼯具,⽐如 Eclipse Memory Analyzer。

16 jvm内存溢出例⼦
  1. 内存溢出,⽐如给JVM分配的内存不够⼤,或者程序中存在死循环⼀直申请内存。
  2. 内存泄露,⽐如下⾯这段代码,list持有o的引⽤,o暂时是⽆法被JVM垃圾回收的,只有当list被垃圾回收或者o从对象list删除掉后,o才能被JVM垃圾回收。

17 常⽤的GC策略,什么时候会触发YGC,什么时候触发FGC?

YGC(Young GC):

  • 概念:对新⽣代堆进⾏GC。频率⽐较⾼,因为⼤部分对象的存活寿命较短,在新⽣代⾥被回收。性能耗费较⼩。
  • 触发时机:Eden区空间不⾜。

FGC(Full GC):

  • 概念:全堆范围的GC。默认堆空间使⽤到达80%(可调整)的时候会触发FGC。以我们⽣产环境为例,⼀般⽐较少会触发FGC,有时10天或⼀周左右会有⼀次。
  • 触发时机:
  • ------ Old空间不⾜;
  • ------ Perm空间不⾜;
  • ------ 显示调⽤System.gc() ,包括RMI等的定时触发;
  • ------ YGC时的悲观策略;
  • ------ dump live的内存信息时(jmap –dump:live)。
18 获得Class对象的方式
  1. 静态类的.class语法:GuideUtil.class
  2. 普通类对象的getClass()⽅法:new Test().getClass()
  3. 通过Class对象的forName()⽅法:
    Class.forName(“com.zhenai.modules.guide.utils.GuideUtil");
  4. 对于包装类,可以通过.TYPE语法⽅式:Integer.TYPE
19 内存溢出的可能原因和解决⽅法
  1. 数据加载过多,如1次从数据库中取出过多数据。
  2. 集合类中有对对象的引⽤,⽤完后没有清空或者集合对象未置空导致引⽤存在等,是的JVM⽆法回收。
  3. 死循环,过多重复对象。
  4. 第三⽅软件的bug。
  5. 启动参数内存值设定的过⼩。

解决⽅法:修改JVM启动参数,加内存(-Xms,-Xmx);错误⽇志,是否还有其他错误;代码⾛查。

20 内存泄漏的原因
  1. 未对作废数据内存单元置为null,尽早释放⽆⽤对象的引⽤,使⽤临时变量时,让引⽤变量在推出活动域后⾃动设置为null。

垃圾收集器收集;

  1. 程序避免⽤String拼接,⽤StringBuffer,因为每个String会占⽤内存⼀块区域;
  2. 尽量少⽤静态变量(全局不会回收);
  3. 不要集中创建对象尤其⼤对象,可以使⽤流操作;
  4. 尽量使⽤对象池,不再循环中创建对象,优化配置;
  5. 创建对象到单例getInstance中,对象⽆法回收被单例引⽤;
  6. 服务器session时间设置过⻓也会引起内存泄漏。
21 ⽅法区oom
  1. ⽅法区⽤于存放Class的相关信息,如:类名,访问修饰符,常量池,字符描述,⽅法描述等。
  2. 原因:运⾏时产⽣⼤量的类去填满⽅法区,直到溢出。
22 哪些情况下对象会进⼊⽼年代?
  1. 新⽣代对象每次经历⼀次minor gc,年龄会加1,当达到年龄阈值(默认为15岁)会直接进⼊⽼年代;
  2. ⼤对象直接进⼊⽼年代;
  3. 新⽣代复制算法需要⼀个survivor区进⾏轮换备份,如果出现⼤量对象在minor gc后仍然存活的情况时,就需要⽼年代进⾏分配担保,让survivor⽆法容纳的对象直接进⼊⽼年代;
  4. 如果在Survivor空间中相同年龄所有对象⼤⼩的总和⼤于Survivor空间的⼀半,年龄⼤于或等于该年龄的对象就可以直接进⼊年⽼代。
23 jvm中哪些地⽅会出现oom?分别说说oom的可能原因?

java堆溢出(heap):

  • Java堆内存主要⽤来存放运⾏过程中所以的对象,该区域OOM异常⼀般会有如下错误信息: java.lang.OutofMemoryError:Java heap space
  • 此类错误⼀般通过Eclipse Memory Analyzer分析OOM时dump的内存快照就能分析出来,到底是由于程序原因导致的内存泄露,还是由于没有估计好JVM内存的⼤⼩⽽导致的内存溢出。
  • 另外,Java堆常⽤的JVM参数:

-Xms:初始堆⼤⼩,默认值为物理内存的1/64(<1GB),默认(MinHeapFreeRatio参数可以调整)空余堆内存⼩于40%时,JVM就会增⼤堆直到

-Xmx:最⼤堆⼤⼩,默认值为物理内存的1/4(<1GB),默认(MaxHeapFreeRatio参数可以调整)空余堆内存⼤于70%时,JVM会减少堆直到

-Xmn:年轻代⼤⼩(1.4or lator),此处的⼤⼩是(eden + 2 survivor space),与jmap -heap中显示的New gen是不同的。

栈溢出(stack):

  • 栈⽤来存储线程的局部变量表、操作数栈、动态链接、⽅法出⼝等信息。如果请求栈的深度不⾜时抛出的错误会包含类似下⾯的信息:java.lang.StackOverflowError。
  • 另外,由于每个线程占的内存⼤概为1M,因此线程的创建也需要内存空间。操作系统可⽤内存-Xmx-MaxPermSize即是栈可⽤的内存,如果申请创建的线程⽐较多超过剩余内存的时候,也会抛出如下类似错误:java.lang.OutofMemoryError: unable to create new native thread
  • 相关的JVM参数有:

-Xss: 每个线程的堆栈⼤⼩,JDK5.0以后每个线程堆栈⼤⼩为1M,以前每个线程堆栈⼤⼩为256K.

在相同物理内存下,减⼩这个值能⽣成更多的线程.但是操作系统对⼀个进程内的线程数还是有限制的,不能⽆限⽣成,经验值在3000~5000

  • 可能原因:

递归:递归⾥⽤到的局部变量存储在堆栈中,堆栈的访问效率⾼,速度快,但空间有限,递归太多变量需要⼀直⼊栈⽽不出栈,导致需要的内存空间⼤于堆栈的空间,栈空间是2M,堆空间内存空间。

运⾏时常量溢出(constant):

  • 运⾏时常量保存在⽅法区,存放的主要是编译器⽣成的各种字⾯量和符号引⽤,但是运⾏期间也可能将新的常量放⼊池中,⽐如String类的intern⽅法。如果该区域OOM,错误结果会包含类似下⾯的信息:java.lang.OutofMemoryError: PermGen space
  • 相关的JVM参数有:

-XX:PermSize:设置持久代(perm gen)初始值,默认值为物理内存的1/64

-XX:MaxPermSize:设置持久代最⼤值,默认为物理内存的1/4

⽅法区溢出:

  • ⽅法区主要存储被虚拟机加载的类信息,如类名、访问修饰符、常量池、字段描述、⽅法描述等。理论上在JVM启动后该区域⼤⼩应该⽐较稳定,但是⽬前很多框架,⽐如Spring和Hibernate等在运⾏过程中都会动态⽣成类,因此也存在OOM的⻛险。如果该区域OOM,错误结果会包含类似下⾯的信息:java.lang.OutofMemoryError: PermGen space
  • 相关的JVM参数有:

-XX:PermSize:设置持久代(perm gen)初始值,默认值为物理内存的1/64

-XX:MaxPermSize:设置持久代最⼤值,默认为物理内存的1/4

24 如何定位jvm内存信息?

方法一:打印⽇志

-XX:+PrintGC:输出形式: 
[GC 118250K->113543K(130112K), 0.0094143 secs] 
[Full GC 121376K->10414K(130112K), 0.0650971 secs]
-XX:+PrintGCDetails:输出形式: 
[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] 
[GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs
-XX:+PrintGCTimeStamps:打印GC停顿耗时
-XX:+PrintGCApplicationStoppedTime:打印垃圾回收期间程序暂停的时间. 
-XX:+PrintHeapAtGC:打印GC前后的详细堆栈信息
-Xloggc:filename:把相关⽇志信息记录到⽂件以便分析.

方法二:错误调试

-XX:ErrorFile=./hs_err_pid<pid>.log:如果JVM crashed,将错误⽇志输出到指定⽂件路径。
-XX:HeapDumpPath=./java_pid<pid>.hprof:堆内存快照的存储⽂件路径。
-XX:-HeapDumpOnOutOfMemoryError:在OOM时,输出⼀个dump.core⽂件,记录当时的堆内存快照

方法三:类状态器相关

-XX:-TraceClassLoading:打印class装载信息到stdout。记Loaded状态。
-XX:-TraceClassUnloading:打印class的卸载信息到stdout。记Unloaded状态。
25 当对象A创建之后,对象A在各个区之间的流转过程

jvm堆结构图:

  • 新⽣代通常占JVM堆内存的1/3,因为新⽣代存储都是新创建的对象,⽐较⼩的对象,⽽⽼年代存的都是⽐较⼤的,活的久的对象,所以⽼年代占JVM堆内存较⼤;
  • 新⽣代⾥的Eden区通常占年轻代的4/5,两个Survivor分别占新⽣代的1/10。因为Survivor中存储的是GC之后幸存的对象,实际上只有很少⼀部分会幸存,所以Survivor占的⽐例⽐较⼩。

对象流转流程(新⽣代复制算法,可以减少内存碎⽚)

  • 对象A被new出来之后,是被存放在Eden(伊甸园)区的。
  • 当发⽣⼀次GC后,Eden区存活下来的对象A会被复制到s1区,s0中存活的对象也会被复制到s1中。

如果对象年龄超过阈值年龄(默认15岁),会被复制到⽼年区。部分对象也需要⽼年代分担。

  • GC会清空Eden和s0中存储的所有对象;
  • 交换s0和s1的⻆⾊;
  • 重复上⾯的步骤。
26 jvm堆持久代

⽤于存放静态类型数据,如 Java Class, Method 等。持久代对垃圾回收没有显著影响。但是有些应⽤可能动态⽣成或调⽤⼀些Class,例如 Hibernate CGLib 等,在这种时候往往需要设置⼀个⽐较⼤的持久代空间来存放这些运⾏过程中动态增加的类型。

27 synchronized和ReentrantLock

synchronized⽤的锁是存在Java对象头⾥的

目录
相关文章
|
4月前
|
缓存 Java 关系型数据库
2025 年最新华为 Java 面试题及答案,全方位打造面试宝典
Java面试高频考点与实践指南(150字摘要) 本文系统梳理了Java面试核心考点,包括Java基础(数据类型、面向对象特性、常用类使用)、并发编程(线程机制、锁原理、并发容器)、JVM(内存模型、GC算法、类加载机制)、Spring框架(IoC/AOP、Bean生命周期、事务管理)、数据库(MySQL引擎、事务隔离、索引优化)及分布式(CAP理论、ID生成、Redis缓存)。同时提供华为级实战代码,涵盖Spring Cloud Alibaba微服务、Sentinel限流、Seata分布式事务,以及完整的D
208 1
|
4月前
|
存储 安全 Java
常见 JAVA 集合面试题整理 自用版持续更新
这是一份详尽的Java集合面试题总结,涵盖ArrayList与LinkedList、HashMap与HashTable、HashSet与TreeSet的区别,以及ConcurrentHashMap的实现原理。内容从底层数据结构、性能特点到应用场景逐一剖析,并提供代码示例便于理解。此外,还介绍了如何遍历HashMap和HashTable。无论是初学者还是进阶开发者,都能从中受益。代码资源可从[链接](https://pan.quark.cn/s/14fcf913bae6)获取。
233 3
|
3月前
|
缓存 Java API
Java 面试实操指南与最新技术结合的实战攻略
本指南涵盖Java 17+新特性、Spring Boot 3微服务、响应式编程、容器化部署与数据缓存实操,结合代码案例解析高频面试技术点,助你掌握最新Java技术栈,提升实战能力,轻松应对Java中高级岗位面试。
341 0
|
4月前
|
存储 安全 Java
2025 最新史上最全 Java 面试题独家整理带详细答案及解析
本文从Java基础、面向对象、多线程与并发等方面详细解析常见面试题及答案,并结合实际应用帮助理解。内容涵盖基本数据类型、自动装箱拆箱、String类区别,面向对象三大特性(封装、继承、多态),线程创建与安全问题解决方法,以及集合框架如ArrayList与LinkedList的对比和HashMap工作原理。适合准备面试或深入学习Java的开发者参考。附代码获取链接:[点此下载](https://pan.quark.cn/s/14fcf913bae6)。
1570 48
|
2月前
|
安全 Oracle Java
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
206 0
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
|
4月前
|
算法 架构师 Java
Java 开发岗及 java 架构师百度校招历年经典面试题汇总
以下是百度校招Java岗位面试题精选摘要(150字): Java开发岗重点关注集合类、并发和系统设计。HashMap线程安全可通过Collections.synchronizedMap()或ConcurrentHashMap实现,后者采用分段锁提升并发性能。负载均衡算法包括轮询、加权轮询和最少连接数,一致性哈希可均匀分布请求。Redis持久化有RDB(快照恢复快)和AOF(日志更安全)两种方式。架构师岗涉及JMM内存模型、happens-before原则和无锁数据结构(基于CAS)。
120 5
|
3月前
|
存储 运维 Kubernetes
Java启动参数JVM_OPTS="-Xms512m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError"
本文介绍了Java虚拟机(JVM)常用启动参数配置,包括设置初始堆内存(-Xms512m)、最大堆内存(-Xmx1024m)及内存溢出时生成堆转储文件(-XX:+HeapDumpOnOutOfMemoryError),用于性能调优与故障排查。
327 0
|
4月前
|
Java API 微服务
2025 年 Java 校招面试全攻略:从面试心得看 Java 岗位求职技巧
《2025年Java校招最新技术要点与实操指南》 本文梳理了2025年Java校招的核心技术栈,并提供了可直接运行的代码实例。重点技术包括: Java 17+新特性(Record类、Sealed类等) Spring Boot 3+WebFlux响应式编程 微服务架构与Spring Cloud组件 Docker容器化部署 Redis缓存集成 OpenAI API调用 通过实际代码演示了如何应用这些技术,如Java 17的Record类简化POJO、WebFlux构建响应式API、Docker容器化部署。
164 5
|
4月前
|
缓存 NoSQL Java
Java Redis 面试题集锦 常见高频面试题目及解析
本文总结了Redis在Java中的核心面试题,包括数据类型操作、单线程高性能原理、键过期策略及分布式锁实现等关键内容。通过Jedis代码示例展示了String、List等数据类型的操作方法,讲解了惰性删除和定期删除相结合的过期策略,并提供了Spring Boot配置Redis过期时间的方案。文章还探讨了缓存穿透、雪崩等问题解决方案,以及基于Redis的分布式锁实现,帮助开发者全面掌握Redis在Java应用中的实践要点。
212 6
|
4月前
|
安全 Java API
2025 年 Java 校招面试常见问题及详细答案汇总
本资料涵盖Java校招常见面试题,包括Java基础、并发编程、JVM、Spring框架、分布式与微服务等核心知识点,并提供详细解析与实操代码,助力2025校招备战。
206 1

热门文章

最新文章

下一篇
日志分析软件