Java教程

面试-java虚拟机

本文主要是介绍面试-java虚拟机,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

JVM运行时数据区域有哪些?

JDK1.8 之前

程序计数器, Java 虚拟机栈, 本地方法栈, 堆, 方法区, 运行时常量池, 直接内存

JDK1.8 之后

程序计数器, Java 虚拟机栈, 本地方法栈, 堆, 元空间, 直接内存

JVM 运行是数据区域哪些是私有的,哪些是共享的?

线程私有的:

  • 程序计数器
  • 虚拟机栈
  • 本地方法栈

线程共享的:

  • 方法区
  • 直接内存 (非运行时数据区的一部分)

JVM 的堆内存被划分成那几块区域,比例是如何的?

在 JDK 7 版本及 JDK 7 版本之前,堆内存被通常被分为下面三部分:

  1. 新生代内存(Young Generation)
  2. 老生代(Old Generation)
  3. 永生代(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 来设置。

对象创建过程经历哪些步骤

  1. 类加载检查
  2. 分配内存
  3. 初始化零值
  4. 设置对象头
  5. 执行 init 方法

如何判断哪些对象已经死亡?

1.引用计数法

给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数器就减 1;任何时候计数器为 0 的对象就是不可能再被使用的。

这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间相互循环引用的问题。

2.可达性分析算法

这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。

常见垃圾收集算法有哪些?

  1. 标记-清除算法
  2. 复制算法
  3. 标记-整理算法
  4. 分代收集算法

垃圾收集器有哪些?(最少写5个)

  1. Serial 收集器

  2. ParNew 收集器

  3. Parallel Scavenge 收集器

  4. Serial Old 收集器

  5. Parallel Old 收集器

  6. CMS 收集器

  7. G1 收集器

类加载过程

加载

  1. 通过全类名获取定义此类的二进制字节流
  2. 将字节流所代表的静态存储结构转换为方法区的运行时数据结构
  3. 在内存中生成一个代表该类的 Class 对象,作为方法区这些数据的访问入口

验证

1. 文件格式验证
         	2. 元数据验证
                   	3. 字节码验证
                             	4. 符号引用认证

准备

​ 为类变量分配内存并设置类变量初始值

解析

​ 解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符7类符号引用进行。

初始化

​ 初始化阶段是执行类构造器 <clinit> ()方法的过程

JVM 中有哪些类加载器

JVM 中内置了三个重要的 ClassLoader,除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自java.lang.ClassLoader

  1. BootstrapClassLoader(启动类加载器) :最顶层的加载类,由 C++ 实现,负责加载 %JAVA_HOME%/lib目录下的 jar 包和类或者或被 -Xbootclasspath参数指定的路径中的所有类。
  2. ExtensionClassLoader(扩展类加载器) :主要负责加载目录 %JRE_HOME%/lib/ext 目录下的 jar 包和类,或被 java.ext.dirs 系统变量所指定的路径下的 jar 包。
  3. 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 进程的内存使用情况使用什么工具

jconsole

这篇关于面试-java虚拟机的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!