文章目录
1.Java 运行时一个类是什么时候被加载的?
一个类在什么时候开始被加载,《Java 虚拟机规范》中并没有进行强制约束,交给了虚拟机
自己去自由实现,HotSpot 虚拟机是按需加载,在需要用到该类的时候加载这个类
2.JVM 一个类的加载过程?
一个类从加载到 jvm 内存,到从 jvm 内存卸载,它的整个生命周期会经历 7 个阶段:
(1)加载(Loading):classpath、jar 包、网络、某个磁盘位置下的类的 class 二进制字节流读进来,在内存中生成一个代表这个类的 java.lang.Class 对象放入元空间,此阶段我们程序员可以干预,我们可以自定义类加载器来实现类的加载
(2)验证(Verification):验证 Class 文件的字节流中包含的信息符合《Java 虚拟机规范》的全部约束要求,保证虚拟机的安全
(3)准备(Preparation):类变量赋默认初始值,int 为 0,long 为 0L,boolean 为 false,引用类型为 null;常量赋正式值
(4)解析(Resolution):把符号引用翻译为直接引用
(5)初始化(Initialization):当我们 new 一个类的对象,访问一个类的静态属性,修改一个类的静态属性,调用一个类的静态方法,用反射 API 对一个类进行调用,初始化当前类,其父类也会被初始化… 那么这些都会触发类的初始化
(6)使用(Using):使用这个类
(7)卸载(Unloading):
①该类所有的实例都已经被 GC,也就是 JVM 中不存在该 Class 的任何实例;
②加载该类的 ClassLoader 已经被 GC;
③该类的 java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法
其中验证、准备、解析三个阶段统称为连接(Linking)
3.一个类被初始化的过程?
(1)类的初始化阶段,Java 虚拟机才真正开始执行类中编写的 Java 程序代码;
(2)进行准备阶段时,变量已经赋过一次系统要求的初始零值,而在初始化阶段,才真正初始化类变量和其他资源
4.继承时父子类的初始化顺序是怎样的?
父类–静态变量
父类–静态初始化块
子类–静态变量
子类–静态初始化块
父类–变量
父类–初始化块
父类–构造器
子类–变量
子类–初始化块
子类–构造器
GC分代年龄为什么最大为15?
因为Object Header采用4个bit位来保存年龄,4个bit位能表示的最大数就是15
JMM是什么?
Java内存模型(简称JMM),是一种规范,它定义了Java虚拟机(JVM)在计算机内存(RAM)中的工作方式,即规范了Java虚拟机与计算机内存之间是如何协同工作的。它规定了一个线程如何以及何时可以看到其他线程修改过的共享变量的值,以及在必须时如何同步的访问共享变量。
什么是happens-before规则?
(1)作用:保证多线程环境下操作的正确性和有序性
(2)A happens-before B保障以下两项内容:
①可见性:B读取到A最新修改的值
②顺序性:编译器优化、处理器重排序等因素不会影响先执行A再执行B的顺序
JVM的主要组成部分
(1)JVM包含两个子系统和两个组件:两个子系统为Class Loader(类加载器)和Execution engine(执行引擎);两个组件为Runtime data area(运行时数据区)、Native Interface(本地接口)。
①Class Loader(类加载器):根据给定的全限定名类名(如:java.lang.Object)来加载到运行时数据区(Running data area)的方法区中(Method Area)。
②Execution engine(执行引擎):执行classes中的指令
③Native Interface(本地库接口):与Native libraries交互,是其它编程语言交互的接口。
④Running data area(运行时数据区):这块就是我们常说的JVM内存
不同虚拟机的运行时数据区可能略微有所不同,但都会遵从Java虚拟机规范,Java虚拟机规范规定的区域分为以下5个部分:
a.程序计数器(Program Counter Register):当前线程所执行的字节码的行号指示器,字节码解
析器的工作是通过改变这个计数器的值,来选取下一条需要执行的 字节码指令,分支、循环、跳
转、异常处理、线程恢复等基础功能,都需要依赖这个 计数器来完成;
b.Java 虚拟机栈(Java Virtual Machine Stacks):用于存储局部变量表、操作 数栈、动态链接、方法出口等信息;
c.本地方法栈(Native Method Stack):与虚拟机栈的作用是一样的,只不过虚 拟机栈是服务 Java方法的,而本地方法栈是为虚拟机调用 Native 方法服务的;
d.Java 堆(Java Heap):Java 虚拟机中内存大的一块,是被所有线程共享 的,几乎所有的对象实例都在这里分配内存;
e.方法区(Methed Area):用于存储已被虚拟机加载的类信息、常量、静态变 量、即时编译后的代码等数据
JVM常用参数
(1)-Xms< size>:设置JVM初始堆内存大小。例如:-Xms256m,表示初始堆内存大小为256MB。
(2)-Xmx< size>:设置JVM最大堆内存大小。例如:-Xmx1024m,表示最大堆内存大小为1024MB。
(3)-Xss< size>:设置每个线程的栈大小。例如:-Xss1m,表示每个线程的栈大小为1MB。
(4)-XX:MetaspaceSize=< size>:设置元空间的初始大小(Java 8中替代了永久代的概念)。例如:-XX:MetaspaceSize=128m,表示元空间初始大小为128MB。
(5)-XX:MaxMetaspaceSize=< size>:设置元空间的最大大小。例如:-XX:MaxMetaspaceSize=256m,表示元空间最大大小为256MB。
(6)-XX:NewSize=< size>:设置新生代的初始大小。例如:-XX:NewSize=128m,表示新生代初始大小为128MB。
(7)-XX:MaxNewSize=< size>:设置新生代的最大大小。例如:-XX:MaxNewSize=256m,表示新生代最大大小为256MB。
(8)-XX:SurvivorRatio=< ratio>:设置新生代中Eden区与Survivor区的比例。例如:-XX:SurvivorRatio=8,表示Eden区与Survivor区的比例为8:1。
-XX:PermSize=< size>:设置永久代的初始大小(仅在Java 7及更早版本中使用)。例如:-XX:PermSize=64m,表示永久代初始大小为64MB。
-XX:MaxPermSize=< size>:设置永久代的最大大小(仅在Java 7及更早版本中使用)。例如:-XX:MaxPermSize=128m,表示永久代最大大小为128MB。
-XX:+UseSerialGC:使用串行垃圾回收器。
-XX:+UseParallelGC:使用并行垃圾回收器。
-XX:+UseConcMarkSweepGC:使用CMS垃圾回收器。
-XX:+UseG1GC:使用G1垃圾回收器。
-XX:+PrintGCDetails:打印详细的垃圾回收信息。