JVM运行时数据区域有哪些?
JDK1.8之前
程序计数器,Java 虚拟机栈,本地方法栈,堆,方法区,运行时常量池,直接内存
JDK1.8之后
程序计数器,Java 虚拟机栈,本地方法栈,堆,元空间,直接内存
JVM运行是数据区域哪些是私有的,哪些是共享的?
线程私有的:
-
程序计数器
-
虚拟机栈
-
本地方法栈
线程共享的:
-
堆
-
方法区
-
直接内存 (非运行时数据区的一部分)
JVM的堆内存被划分成那几块区域,比例是如何的?
在 JDK 7 版本及JDK 7 版本之前,堆内存被通常被分为下面三部分:
-
新生代内存(Young Generation)
-
老生代(Old Generation)
-
永生代(Permanent Generation)
老年代与新生代比例为2:1。新生代分为一个Eden和两个Survivor区域,比例为8:1:1。
在JDK1.8之后,永生代(Permanent Generation)被移除,取而代之的是元空间
对象经过几次GC之后可以从新生代变成老生代?
默认15次.
对象都会首先在 Eden 区域分配,在一次新生代垃圾回收后,如果对象还存活,则会进入 s0 或者 s1,并且对象的年龄还会加 1(Eden 区->Survivor 区后对象的初始年龄变为 1),当它的年龄增加到一定程度(默认为 15 岁),就会被晋升到老年代中。对象晋升到老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold
来设置。
对象创建过程经历哪些步骤
-
类加载检查
-
分配内存
-
初始化零值
-
设置对象头
-
执行 init 方法
如何判断哪些对象已经死亡?
1.引用计数法
给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数器就减 1;任何时候计数器为 0 的对象就是不可能再被使用的。
这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间相互循环引用的问题。
2.可达性分析算法
这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。
常见垃圾收集算法有哪些?
-
标记-清除算法
-
复制算法
-
标记-整理算法
-
分代收集算法
垃圾收集器有哪些?(最少写5个)
-
Serial 收集器
-
ParNew 收集器
-
Parallel Scavenge 收集器
-
Serial Old 收集器
-
Parallel Old 收集器
-
CMS 收集器
-
G1 收集器
类加载过程
加载
-
通过全类名获取定义此类的二进制字节流
-
将字节流所代表的静态存储结构转换为方法区的运行时数据结构
-
在内存中生成一个代表该类的 Class 对象,作为方法区这些数据的访问入口
验证
1. 文件格式验证 2. 元数据验证 3. 字节码验证 4. 符号引用认证
准备
为类变量分配内存并设置类变量初始值
解析
解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符7类符号引用进行。
初始化
初始化阶段是执行类构造器 <clinit> ()
方法的过程
JVM中有哪些类加载器
JVM 中内置了三个重要的 ClassLoader,除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader
:
-
BootstrapClassLoader(启动类加载器) :最顶层的加载类,由C++实现,负责加载
%JAVA_HOME%/lib
目录下的jar包和类或者或被-Xbootclasspath
参数指定的路径中的所有类。 -
ExtensionClassLoader(扩展类加载器) :主要负责加载目录
%JRE_HOME%/lib/ext
目录下的jar包和类,或被java.ext.dirs
系统变量所指定的路径下的jar包。 -
AppClassLoader(应用程序类加载器) :面向我们用户的加载器,负责加载当前应用classpath下的所有jar包和类。
解释一下双亲委派模型
每一个类都有一个对应它的类加载器。系统中的 ClassLoder 在协同工作的时候会默认使用 双亲委派模型 。即在类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。加载的时候,首先会把该请求委派该父类加载器的 loadClass()
处理,因此所有的请求最终都应该传送到顶层的启动类加载器 BootstrapClassLoader
中。当父类加载器无法处理时,才由自己来处理。当父类加载器为null时,会使用启动类加载器 BootstrapClassLoader
作为父类加载器。
双亲委派模型的好处
双亲委派模型保证了Java程序的稳定运行,可以避免类的重复加载(JVM 区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类),也保证了 Java 的核心 API 不被篡改。如果没有使用双亲委派模型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 java.lang.Object
类的话,那么程序运行的时候,系统就会出现多个不同的 Object
类。
如果我们不想用双亲委派模型怎么办?/如何破坏双亲委派机制?
为了避免双亲委托机制,我们可以自己定义一个类加载器,然后重写 loadClass()
即可。
如何自定义类加载器
除了 BootstrapClassLoader
其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader
。如果我们要自定义自己的类加载器,很明显需要继承 ClassLoader
。
如果需要设置JVM分配最小2 GB和最大5 GB的堆内存大小,参数如何写?
-Xms2G -Xmx5G
JDK中看出所有Java进程使用哪个命令?
jps
监视虚拟机各种运行状态信息可以使用哪个命令?
jstat
试试查看和调整虚拟机各项参数使用哪个命令
jinfo
监视视本地及远程服务器的 java 进程的内存使用情况使用什么工具
jconsoleM