jvm面试常问

类的加载机制

Java的类加载机制是Java虚拟机(JVM)运行时负责加载类文件并将其转换成可执行的字节码的过程。类加载机制主要包括以下三个步骤:加载(Loading)、链接(Linking)、初始化(Initialization)。这三个步骤统称为类加载过程。

  • 加载(Loading):

加载是指将类的二进制数据读入到内存中,并生成一个代表该类的 java.lang.Class 对象。类加载器通过类的全限定名(Fully Qualified Name)来定位和加载类的字节码。

  • 链接(Linking):

链接阶段包括三个步骤:验证(Verification)、准备(Preparation)、解析(Resolution)。
验证: 确保被加载的类是合法、符合规范的。主要验证类的格式、语义、字节码等。
准备: 为类的静态变量分配内存,并设置默认初始值。
解析: 将类、接口、字段和方法的符号引用解析为直接引用。

  • 初始化(Initialization):

在这个阶段,类的静态变量会被赋予初始值,静态代码块会被执行。这是类加载过程的最后一步,也是真正意义上类加载完成的时刻。在初始化阶段,虚拟机会保证一个类的初始化是线程安全的,即只会执行一次。


java内存区域的介绍

Java 内存区域是Java虚拟机(JVM)在运行过程中管理的不同内存区域,用于存储不同类型的数据和执行不同的操作。Java内存区域主要包括以下几个部分:

  • 方法区(Method Area):

方法区是被所有线程共享的内存区域,用于存储类信息、常量、静态变量、即时编译器编译后的代码等。在HotSpot虚拟机中,方法区被称为"永久代"(Permanent Generation),但在Java 8及以后的版本中,永久代被元空间(Metaspace)所替代。

  • Java 堆(Heap):

堆是用于存储对象实例的内存区域,是Java虚拟机管理的最大的一块内存。堆被所有线程共享,是垃圾回收的主要工作区域。

  • 虚拟机栈(Stack):

栈是线程私有的内存区域,每个线程都有自己的栈。栈用于存储局部变量、方法调用、方法返回等信息。栈帧(Stack Frame)是栈的基本组成单元,每个方法调用都会创建一个栈帧。栈是一个后进先出(LIFO)的数据结构。

  • 本地方法栈(Native Method Stack):

本地方法栈与栈类似,用于存储调用本地方法(Native Method)时的信息。每个线程都有自己的本地方法栈。

  • 程序计数器(Program Counter Register):

用于存储当前线程执行的字节码地址。每个线程都有自己的PC寄存器,保证线程切换后能够恢复到正确的执行位置。


jvm垃圾回收机制

  • 标记-清除算法(Mark and Sweep):

标记阶段: 从根节点出发,标记所有能够被访问到的对象。
清除阶段: 清除所有未被标记的对象,释放其占用的内存空间。
缺点: 会产生内存碎片,影响分配大对象。

  • 复制算法(Copying):

将堆分为两个区域,一半为活动对象,一半为空闲。
活动对象区域满了后,将存活的对象复制到另一半空闲区域,同时清理掉已经使用的区域。
缺点: 只能使用一半的内存,适用于新生代。

  • 标记-整理算法(Mark and Compact):

类似于标记-清除,但标记后会将存活对象向一端移动,然后清理掉边界以外的部分。
相对于标记-清除,减少了内存碎片。

  • 分代收集算法(Generational Collection):

将堆分为新生代和老年代,每代使用不同的垃圾回收算法。
新生代一般使用复制算法,老年代一般使用标记-清除或标记-整理算法。
优势: 利用了对象的生命周期长短不同的特点,新生代的对象生命周期短,老年代的对象生命周期长。

  • 并行垃圾回收算法(Parallel Garbage Collection):

使用多个线程同时进行垃圾回收,提高回收效率。
主要包括并行标记-清除(Parallel Mark and Sweep)、并行复制(Parallel Scavenge)等。

  • CMS算法(Concurrent Mark-Sweep):

在标记和清理阶段尽量与应用程序线程并发执行,减少停顿时间。
首先进行初始标记、并发标记、重新标记,最后是并发清理。

  • G1算法(Garbage First):

将堆划分为多个独立的区域,包括新生代、老年代和一部分混合区域。
根据垃圾回收的预期停顿时间优化,尽量在用户线程运行的同时进行垃圾回收。


什么是GC,作用是什么

GC是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,

忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,

Java语言没有提供释放已分配内存的显示操作方法。Java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc()或Runtime.getRuntime().gc(),但JVM可以屏蔽掉显示的垃圾回收调用。 

垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低优先级的线程运行不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。

在Java诞生初期,垃圾回收是Java最大的亮点之一,因为服务器端的编程需要有效的防止内存泄露问题,然而时过境迁,如今Java的垃圾回收机制已经成为被诟病的东西。移动智能终端用户通常觉得iOS的系统比Android系统有更好的用户体验,其中一个深层次的原因就在于Android系统中垃圾回收的不可预知性。


解释一下synchronized 关键字

Java 中的锁分为显示锁和隐式锁。

隐式锁由 synchronized 关键字实现。

显示锁由 Lock 接口和 AQS 框架等等类来实现。

Java 中的每⼀个对象都可以作为锁,有三种加锁的⽅式:
(1)对于普通同步⽅法,锁是当前实例对象。
(2)对于静态同步⽅法,锁是当前类的 Class 对象
(3)对于同步⽅法块,锁是 Synchonized 括号⾥配置的对象。


JVM 启动时都有哪些参数

「堆内存相关」
-Xms :设置初始堆的大小
-Xmx :设置最大堆的大小
-Xmn :设置年轻代大小,相当于同时配置 -XX:NewSize和 -XX:MaxNewSize 为一样的值
-Xss :每个线程的堆栈大小
-XX:NewSize :设置年轻代大小(for 1.3/1.4)
-XX:MaxNewSize :年轻代最大值(for 1.3/1.4)
-XX:NewRatio :年轻代与年老代的比值(除去持久代)
-XX:SurvivorRatio :Eden区与Survivor区的的比值
-XX:PretenureSizeThreshold :当创建的对象超过指定大小时,直接把对象分配在老年代
-XX:MaxTenuringThreshold :设定对象在Survivor复制的最大年龄阈值,超过阈值转移到老年代
「垃圾收集器相关」
-XX:+UseParallelGC :选择垃圾收集器为并行收集器
-XX:ParallelGCThreads=20 :配置并行收集器的线程数
-XX:+UseConcMarkSweepGC :设置年老代为并发收集
-XX:CMSFullGCsBeforeCompaction=5 :由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行5次GC以后对内存空间进行压缩、整理
-XX:+UseCMSCompactAtFullCollection :打开对年老代的压缩。可能会影响性能,但是可以消除碎片
「辅助信息相关」
-XX:+PrintGCDetails :打印GC详细信息
-XX:+HeapDumpOnOutOfMemoryError :让JVM在发生内存溢出的时候自动生成内存快照,用于排查问题
-XX:+DisableExplicitGC禁止系统System.gc() :防止手动误触发FGC造成问题.
-XX:+PrintTLAB :查看TLAB空间的使用情况

  • 23
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值