Java基础面试题整理(二)-- JVM

Java平台无关性如何实现

在这里插入图片描述
Java源码首先被编译成字节码,再由不同平台的JVM进行解析,Java语言在不同的平台 上运行的时候不需要进行重新编译,Java虚拟机在执行字节码的时候,把字节码转换成具体平台上的机器指令。

为什么JVM不直接将源码解析成机器码去执行

  • 准备工作:每次执行都需要各种检查;
  • 兼容性:可以将别的语言解析成字节码;

JVM如何加载class文件

在这里插入图片描述

  • ClassLoader:依照特定格式,加载class文件到内存;
  • Execution Engine:对命令进行解析;
  • Native Interface:融合不同开发语言的原生库为Java所用;

什么是反射?

Java的反射机制就是在运行状态中,对于任意一个类,都能够知道这个的所有属性和方法;对于任意一个对象都能够调用它的任意方法和属性,这种动态获取信息以及动态调用对象方法的功能成为Java 的反射机制

写一个反射的例子
//对象类
public class Robot {
    private String name;
    public void sayHi(String helloSentence){
        System.out.println(helloSentence + " " + name);
    }
    private String throwHello(String tag){
        return "Hello " + tag;
    }
    static {
        System.out.println("Hello Robot");
    }
}
mport java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectSample {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {
    	//获取类对象
        Class rc = Class.forName("com.interview.javabasic.reflect.Robot");
        // 
        Robot r = (Robot) rc.newInstance();
        System.out.println("Class name is " + rc.getName());
        Method getHello = rc.getDeclaredMethod("throwHello", String.class);
        getHello.setAccessible(true);
        Object str = getHello.invoke(r, "Bob");
        System.out.println("getHello result is " + str);
        Method sayHi = rc.getMethod("sayHi", String.class);
        sayHi.invoke(r, "Welcome");
        Field name = rc.getDeclaredField("name");
        name.setAccessible(true);
        name.set(r, "Alice");
        sayHi.invoke(r, "Welcome");
        System.out.println(System.getProperty("java.ext.dirs"));
        System.out.println(System.getProperty("java.class.path"));

    }
}

谈谈ClassLoader

ClassLoader在Java中有着非常重要的作用,它主要工作在Class装载的加载阶段,其主要作用是从系统外部获得Class的二进制工作流,它是Java的核心组件,所有的Class都是由ClassLoader进行加载的,ClassLoader负责通过将Class文件里的二进制数据流加载进系统,然后交给Java虚拟机进行连接、初始化等操作。

  • BootStrapClassLoader: C++编写,加载核心库java.*;
  • ExtClassLoader: Java编写,加载扩展库 javax.*;
  • AppClassLoader: Java编写,加载程序所在目录;
  • 自定义ClassLoader: Java编写,定制化加载;

类加载器的双亲委派机制

在这里插入图片描述

  • 避免多份同样的字节码的加载;

类的加载方式

  • **隐式加载: ** new
  • 显式加载: laadClass、forName;

类加载过程:

  • 加载: 通过ClassLoader加载class文件字节码,生成Class对象;
  • 链接
    • 校验:检查加载的class的正确性和安全性;
    • 准备:为类变量分配存储空间并设置类变量的初始值(static修饰的变量);
    • 解析:JVM将常量池内的符号引用转化为直接引用;
  • 初始化: 执行类变量赋值和静态代码块;

loadClass和forName的区别:

  • Class.forName()得到的class是已经得到初始化完成的,Classloader.loadClass得到的class 是还没有链接的;
  • Classloader.loadClass 在实现Spring的延迟加载时作用很大;

谈谈Java的内存模型

内存简介

在这里插入图片描述

地址空间的划分

  • 内核空间
  • 用户空间

JVM架构

  • ClassLoader:依据特定格式,加载class文件到内存;
  • ExecutionEngine:对命令进行解析;
  • NativeInterface:融合不同开发语言的原生库为Java所用;
  • Runtime Data Area: JVM内存空间结构模型;

JVM内存模型–JDK8

在这里插入图片描述

  • 线程私有的:程序计数器、虚拟机栈、本地方法栈;
  • 线程共享:MetaSpace、Java堆;
线程私有–程序计数器
  • 当前线程所执行的字节码行号指示器(逻辑),逻辑计数器
  • 改变计数器的值来选取下一条需要执行的字节码指令;
  • 和线程是一对一的关系,即"线程私有";
  • 对Java方法计数,如果是Native方法计数器值为Undefined;
  • 不会发生内存泄漏;
线程私有–Java虚拟机栈(Stack)
  • Java方法执行的内存模型,每次方法的调用都是通过虚拟机栈传递的;
  • 包括多个栈帧(局部变量表、操作栈、动态链接、返回地址);
    • 局部变量表: 包含方法执行过程中的所有变量;
    • 操作数栈: 入栈、出栈、复制、交换、产生消费变量;
线程私有–Java本地方法栈
  • 与虚拟机栈相似,主要作用于native方法栈;
线程共享–MetaSpace(元空间)
  • 元空间使用本地内存,而永久代使用的是jvm内存;
    • 字符串常量池存在永久代中,容易出现性能问题和内存溢出;
    • 类和方法的信息大小难易确定,给永久代的大小指定带来困难;
    • 永久代会给GC带来不必要的复杂性;
线程共享–堆(Heap)
  • 堆区域的唯一目的就是存放对象实例的区域,是Java虚拟机管理内存中最大的一块区域;
    在这里插入图片描述
  • GC管理的主要区域;
    在这里插入图片描述
说一下JVM三大性能调优参数 -Xms、-Xmx、-Xss的含义
  • -Xss: 规定了每个线程虚拟机栈(堆栈)的大小;
  • -Xms: 堆的初始值;
  • -Xmx: 堆能达到的最大值,一般Xms和Xmx的值一样;
Java内存模型堆和栈的区别–内存分配策略;

1、存储区别

  • 静态存储: 编译时就能确定每个数据目标在运行时的存储空间需求;
  • 栈式存储: 数据区需求在编译时未知,运行时模块入口确定;
  • 堆式存储: 编译时或运行时模块入口都无法确定,动态分配;

2、联系

  • 引用对象、数组时候,栈里会定义变量保存堆中目标的首地址;
    在这里插入图片描述
  • 管理方式:栈自动释放,堆需要GC;
  • 空间大小:栈比堆小;
  • 碎片相关:栈产生的碎片远小于堆;
  • 分配方式:栈支持静态和动态分配,堆仅支持动态分配
  • 效率:栈的效率比堆高;

垃圾回收

对象被判定为垃圾的标准

  • 没有被对象引用
    • 引用计数法:通过判断的引用数量来决定镀锡是否可以被回收,每个对象实例都有一个引用计数器,被引用则+1,完成引用则-1,任何引用计数为0的对象实例可以被当做垃圾收集;
    • 可达性分析算法:通过判断对象的引用链是否可达来决定对象是否可以被回收;
      在这里插入图片描述
      • 虚拟机栈中引用的对象(栈帧中的本地变量表);
      • 方法区中常量引用的对象;
      • 方法区中类静态属性引用的对象;
      • 本地方法栈中引用对象;
      • 活跃线程的引用对象;

垃圾回收算法

标记-清除算法
  • 标记:从 根集合进行扫描,对存活的对象进行标记;
  • 清除:对堆内存从头到尾进行线性遍历,回收不可达对象内存;
    在这里插入图片描述
复制算法(适合年轻代中的对象)
  • 可用内存分为对象面和空闲面;
  • 对象在对象面上创建,存活的对象被从对象面复制到空闲面;
  • 将对象面所有对象面内存清除;
标记-清除算法(适合老年代中的对象)
  • 标记:从根集合进行扫描,对存货的对象进行标记;
  • 清除:移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收;
  • 优点:
    1、避免内存的不连续;
    2、不用设置两块内存互换;
    3、适用于存活率高的场景;
分代收集算法
  • 垃圾回收的集大成者,按照对象生命周期的不同划分区域以采用不同的垃圾回收算法,提高垃圾回收效率;
  • 年轻代对象存活率低,使用复制算法;老年代对象存活率高,使用标记-整理或者标记-清除算法;
年轻代:尽可能快速收集掉那些生命周期短的对象
  • Eden区(8):新创建的对象在Eden去内存足够的情况下存在;
  • 两个Survivor区(1:1):
    在这里插入图片描述
    对象如何晋升到老年代
  • 经历一定Minor次数依然存活的对象;
  • Survivor区中存放不下的对象;
  • 新生成的大对象(-XX:+PretenuerSizeThreshold)
    常用的调优参数
  • -XX:SurvivorRatio: Eden区和Survivor区的比值,默认8:1;
  • -XX:NewRatio: 老年代和你年轻代内存大小的比例;
  • -XX:MaxTenuringThreshold: 对象从年轻代晋升到老年代经过GC次数的阈值;
老年代:存放生命周期较长的对象

在这里插入图片描述

  • 使用标记清理或标记整理算法进行垃圾回收;
  • 触发老年代的垃圾回收指的是Full GC或Major GC;
  • Full GC比Minor GC慢;
    触发Full GC的条件:
  • 老年代空间不足;
  • CMS GC时出现promotion failed和concurrent mode failure;
  • MinorGC晋升到老年代的平均大小大于老年代的剩余空间;
  • 调用System.gc()可能会触发Full GC;

Stop-the-World

  • JVM要执行垃圾回收而停止了应用程序的执行;
  • 任何一种GC算法中都会发生;
  • 多数GC优化通过减少Stop-the-world发生的时间来提高性能;

GC的分类

  • Minor GC:发生在年轻代中;
  • Full GC:发生在老年代中;

常见的垃圾收集器

JVM的运行模式
  • Server
  • Client
垃圾收集器之间的联系

在这里插入图片描述

年轻代收集器

Serial收集器(-XX:UserSerial,复制算法)
  • 单线程收集:进行垃圾收集时候,必须暂停所有工作线程;
  • 简单高效:Client默认下默认的年轻代收集器;
ParNew收集器(-XX:+UseParNewGC,复制算法)
  • 多线程收集,其余的行为、特点和Serial收集器一样;
  • 单核执行效率不如Serial,在多核下执行才有优势;
Parallel Scavenge收集器(-XX:+UseParallelGC,复制算法)
  • 更关注系统的吞吐量;
  • 在多核下执行才有优势,Server模式下默认的年轻代收集器;

老年代收集器

Serial Old收集器(-XX:+UseSerialOldGC,标记-整理算法)
  • 单线程收集,进行垃圾收集时,必须暂停所有工作线程;
Parallel Old收集器(-XX:+UseParallelOldGC,标记-整理算法)
  • 单线程。吞吐量优先;
CMS收集器(-XX:+UseConcMarkSweepGC,标记-清除算法)
  • 初始标记:stop-the-world
  • 并发标记:并发追溯标记,程序不会停顿;
  • 并发预清理:查找执行并发标记阶段从年轻代晋升到老年代的对象;
  • 重新标记:暂停虚拟机,扫描CMS堆中的剩余 对象;
  • 并发清理:清理垃圾对象,程序不会停顿;
  • 并发重置:重置CMS收集器的数据结构;
    在这里插入图片描述
G1收集器(-XX:+UseG1GC,复制+标记-整理算法)
  • 并行和并发;
  • 分代收集;
  • 空间整合;
  • 可预测的停顿;

GC相关面试题

Java中的强引用、软引用、弱引用、虚引用

  • 强引用:
    • 最普遍的引用:Object object = new Object();
    • 抛出OOM异常终止程序也不会回收具有强引用的对象;
    • 通过将对象设置为null来弱化引用,使其被回收;
  • 软引用
    • 对象处在有用但非必须的状态;
    • 只有当内存空间不足时,GC会回收该引用的对象的内存;
    • 可以用来实现高速缓存;
  • 弱引用
    • 非必须的对象,比软引用更弱一些;
  • 虚引用
    • 不会决定对象的生命周期;
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值