面试题【JVM】

jvm内存模型

分为:虚拟机栈、堆、方法区、本地方法栈、程序计数器

虚拟机栈:每个线程都有一个私有的栈,随着线程的创建而创建。栈中存放了局部变量表(基本数据类型和对象引用)、方法出口等信息。栈的大小是固定的(也可以动态扩展,jvm未实现,需自己实现,将多个栈用链表连接起来)。如果超出栈的深度,会抛出StackOverflowError(栈溢出)错误

本地方法栈:主要是虚拟机用到的本地方法

程序计数器:jvm支持多个线程同时运行。每个线程都有自己的程序计数器。其保存的是当前执行的指令地址。

:是所有线程共享的地方,在虚拟机启动时就已创建。所有对象和数组都在堆内存上进行分配,这部分空间会被GC进行回收。当申请不到空间时会抛出OutOfMemoryError。堆内存溢出异常

方法区:所有线程共享。主要存储类信息,常量池,方法代码,方法数据等

内存溢出与内存泄漏

内存泄漏

对象可达,但是未被使用,一直占用内存空间,不会被GC进行回收。

举例:

Vector v=new Vector(10);
for (int i=1;i<100; i++)
{
    Object o=new Object();
    v.add(o);
    o=null; 
}

对象o放入到容器v中,然后设置为null(内存释放),但由于容器还引用此对象,所以GC并不会进行回收。

内存溢出

如果内存泄漏严重,就会导致内存溢出(大量无用对象一直未被回收,导致内存空间不足)

JVM年轻代晋升到年老代过程

部分对象会在Survivor From和Survivor To区中复制来复制去(默认交换15次),如果最终存活,就存入到老年代

Survivor为什么会有两个?始终保持一个空的Survivor区,可以避免内存碎片化

fullGC频繁怎么排查

full gc是发生在老年代的垃圾回收动作,采用的算法是:标记-清除算法。

当老年代没有足够空间时,会触发full gc

  1. 查看老年代(jdk1.8没有永久代)值设置是否过于小
  2. 是否有主动full gc的调用 System.gc();
  3. 是不是频繁创建来大对象(大对象,将直接进入老年代)

如果一次full gc后,剩余对象不多,说明Eden区设置太小,导致短生命old区;

如果一次full gc后,old区回收率不大,说明old区太小;

堆内存划分

划分为:新生代(Eden,S0,S1),老年代。

这样划分是为了使jvm能够更好的管理内存中的对象,包括内存的分配及回收

根据堆的分区,垃圾回收分为两种:Minor GC、Full GC

年轻代:存放最新创建的对象

分为3个区域:Eden,Survivor0,Survivor1。

当发生Minor GC,会将新生代和S From中的对象复制到S To区域中。如果在指定次数回收后仍然存在存活的对象,将会移动到年老代中。算法使用的是复制算法,每个对象都标注存活的年龄,如果对象年龄超过15(默认),就会成为年老代

年老代是full gc的主要区域,采用的是标记-清除算法。都是存活久的对象,所以full gc次数不频繁。每一次full gc都需要花费较久的时间

永久代是方法区的一种实现,不是堆内存的一部分

(可以设置其大小,也可以设置年轻代与年老代的大小比例)

MinorGC

当Eden区分配满时,触发MinorGC操作

算法

标记-清除:首先标记所有需要回收u的对象,标记完成后统一回收被标记的对象

复制:将内存容量大小相等的两块,每次只使用其中一块。当一块内存块使用完,就将活着的对象复制到另一块内存上,然后把原先的内存空间清除掉。

标记-压缩:标记出存活的对象,让其向一端移动,然后清理掉边界以外的内存

分代收集:将java堆进行分代,然后根据其特点采用适当的算法

判断对象是否存活:

引用计数法:每引用一次计数+1,失去引用计数-1(难以解决对象之间循环引用问题)

可达性算法:主流使用。从GC ROOT

G1与CMS收集器

https://blog.csdn.net/rlnlo2pnefx9c/article/details/79722384

G1,是一款面向服务器的垃圾回收器,主

要针对配备多颗处理器及大容量内存的机器,具备高吞吐量性能。整体来看是基于标记-整理算法实现。局部看是复制算法的实现。(响应量有限的并发收集器)

CMS,以最短回收停顿时间为目标的收集器,需要消耗额外的cpu和内存资源。在cpu和内存资源紧张时,会加重系统负担。运行在java虚拟机的老年代中,基于标记-清除算法实现的。(吞吐量优先的并行收集器)

JVM参数与调优

jvm对内存的划分,设置垃圾收集器

跨系统运行

java编译生成.class文件交由jvm解析运行

jvm是跨系统的,所以java就做到了一次编译,到处运行

.class文件会被直接加载到jvm中吗?

java类的加载是动态的,并不会将所有类全部加载后在运行,而是保证程序运行的基础类被完全加载到jvm,至于其他类,只有需要的时候才加载,这是为了节省内存开销。

对类进行初始化:new对象,反射加载,初始化子类父类也被加载,程序运行所需的基类

如何将类加载到jvm中

class文件是通过类的加载机制装载到jvm中的

类加载器有4种:

  1. Bootstrap ClassLoader 启动类加载器(负责加载JAVA-HOME/jre/lib/rt.jar的class文件,由C++实现)
  2. ExtcClassLoader 扩展类加载器(负责加载java平台中扩展功能的一些jar,AVA-HOME/jre/lib/*.jar)
  3. AppClassLoader应用类加载器(负责加载classpath中指定的jar包和class文件)
  4. 自定义类加载器

加载过程是双亲委派模型。即,如果一个类加载器收到了类加载器的请求,它首先不会自己尝试去加载,而是把请求委托给父加载器去完成,以此向上。

  • 1、当AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成。
  • 2、当ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。
  • 3、如果BootStrapClassLoader加载失败(例如在$JAVA_HOME/jre/lib里未查找到该class),会使用ExtClassLoader来尝试加载;
  • 4、若ExtClassLoader也加载失败,则会使用AppClassLoader来加载
  • 5、如果AppClassLoader也加载失败,则会报出异常ClassNotFoundException

好处是:防止内存中出现多份同样的字节码

类加载详细过程

  • 加载(查找并加载类的二进制数据,并创建类对象)
  • 连接(验证,准备,初始化)
  1. 验证:验证文件格式、元数据、字节码、符号引用
  2. 准备:为类的静态变量分配内存,并为其初始化默认值
  3. 解析:把类中的符号引用转换为直接引用
  • 初始化()

jdk8下的jvm变化

JDK8把存放元数据中的永久内存从堆内存中转移到了本地内存,这样就不会报永久内存不够的错误。

提供了设置元空间大小的参数。如果不设置,将会自动增加元空间。

好处是:不需要进行调优及监控内存的使用情况。(并不能消除内存泄漏)

默认情况下,元空间大小只受本地内存限制

元空间的垃圾回收:在达到MaxMetaspaceSize设置的参数设定值时,将会进行垃圾回收

如果元空间经常进行垃圾回收,说明内存泄漏活着设置的大小不合适

类实例化顺序

  1.  父类静态成员和静态初始化块 ,按在代码中出现的顺序依次执行
  2. 子类静态成员和静态初始化块 ,按在代码中出现的顺序依次执行
  3. 父类实例成员和实例初始化块 ,按在代码中出现的顺序依次执行
  4. 父类构造方法
  5. 子类实例成员和实例初始化块 ,按在代码中出现的顺序依次执行
  6. 子类构造方法
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java虚拟机(JVM)是Java程序运行的基础,因此在Java的在线面试中,经常会涉及到JVM相关的问题。面试官可能会问到JVM的内存模型、Java的类加载机制、常用的垃圾回收算法等知识点。在JVM中,有几个重要的内存区域,包括方法区、堆、Java虚拟机栈和本地方法栈。 方法区是堆的一个逻辑部分,用于存放已经被虚拟机加载的类信息、常量、静态变量和即时编译器编译后的代码。方法区是线程共享的区域,也被称为非堆。\[2\] 堆是Java程序运行时动态分配内存的地方,用于存放对象实例和数组。堆是线程共享的区域,所有线程都可以访问堆中的对象。\[2\] Java虚拟机栈是描述Java方法运行过程的内存模型。每个即将运行的Java方法都会创建一个栈帧,用于存放方法运行过程中的信息,包括局部变量表、操作数栈、动态链接和方法出口信息等。方法的执行过程就是栈帧的压栈和出栈的过程。\[3\] 本地方法栈用于支持Java程序调用本地方法,本地方法栈的作用类似于Java虚拟机栈,但是它是为本地方法服务的。\[3\] 在面试中,可能会涉及到JVM的内存模型、类加载机制、垃圾回收算法等知识点。了解这些知识点可以帮助我们更好地理解Java程序的运行机制,并能够在面试中给出准确的答案。 #### 引用[.reference_title] - *1* [JVM 基础学习](https://blog.csdn.net/wwxy1995/article/details/102965778)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [java面试题jvm常见的5道面试题](https://blog.csdn.net/m0_63270506/article/details/124367177)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值