面试题—JVM

本文参照:<面试必问之JVM篇>

目录

  • 1.什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?
  • 2.Java内存结构?
  • 3.讲讲什么情况下会出现内存溢出,内存泄漏?
  • 4.java类的生命周期
  • 5.JVM类加载器有哪些?
  • 6.什么是GC
  • 7.对象在内存中的状态(了解)
  • 8.了解finalize()吗?
  • 9.强制垃圾回收?
  • 10.对象的引用类型

1.什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?

可执行字节码文件的虚拟计算机。是java程序实现跨平台的关键部分。java源文件通过javac编译成.class字节码文件,然后再通过jvm将每一条指令翻译成不同平台机器码,通过特定平台运行。

2.Java内存结构?

面试题—JVM_第1张图片
1)虚拟机栈(JVM Stacks)是线程私有的,随着线程的创建而创建。栈里面存着的是一种叫“栈帧”的东西,每个方法会创建一个栈帧,栈帧中存放了局部变量表(基本数据类型和对象引用)、操作数栈、方法出口等信息。栈的大小可以固定也可以动态扩展。当栈调用深度大于JVM所允许的范围,会抛出StackOverflowError的错误,不过这个深度范围不是一个恒定的值,
2)本地方法栈(Native Method Stacks):这部分主要与虚拟机用到的 Native 方法相关。
3)PC寄存器:也叫程序计数器。每个线程都有自己的程序计数器,倘若当前执行的是 JVM 的方法,则该寄存器中保存当前执行指令的地址;倘若执行的是native 方法,则PC寄存器中为空。
4)堆(Heap):堆内存是 JVM 所有线程共享的部分,在虚拟机启动的时候就已经创建。所有的对象和数组都在堆上进行分配。这部分空间可通过 GC 进行回收。当申请不到空间时会抛出 OutOfMemoryError。
5)方法区(Method Area)又称为持久代,是所有线程共享区域。存放所加载类的信息(名称,修饰符等等),类中的静态变量,final修饰的常量,类中的方法信息等,在一定条件下也会被GC。
常量池:常量池是方法区的一部分。用来存放类中固定的常量信息。
备注:
方法区和堆是所有线程共享的内存区域;而java栈、本地方法栈和程序员计数器是运行是线程私有的内存区域。
JDK1.8中将持久代改成了元空间。元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。

<参照>

3.讲讲什么情况下会出现内存溢出,内存泄漏?

内存泄漏的原因很简单:对象是可达的(一直被引用),但是对象不会被使用。

内存溢出的原因:
内存泄露导致堆栈内存不断增大,从而引发内存溢出。
大量的jar,class文件加载,装载类的空间不够,溢出
操作大量的对象导致堆内存空间已经用满了,溢出
nio直接操作内存,内存过大导致溢出

解决:
查看程序是否存在内存泄漏的问题
设置参数加大空间
代码中是否存在死循环或循环产生过多重复的对象实体、
查看是否使用了nio直接操作内存。

4.java类的生命周期

它的整个生命周期包括,加载 ,连接 , 初始化 ,使用 , 卸载 。其中连接分为验证 ,准备 , 解析 。

  • 加载:将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载由加载器完成,类加载器通常由JVM提供。开发者可以通过继承ClassLoader来创建自己的类加载器。

  • 连接:连接又包含三块内容:验证、准备、解析。
    验证:文件格式、元数据、字节码、符号引用验证。
    准备:为类的静态变量分配内存,并将其初始化为默认值;
    解析:把类中的符号引用转换为直接引用

  • 初始化:为类的静态变量赋予正确的初始值

  • 使用:在程序中使用

  • 卸载:执行垃圾回收

5.JVM类加载器有哪些?

面试题—JVM_第2张图片

  • 启动类加载器(Bootstrap ClassLoader):它用来加载Java的核心库(JAVA_HOME/jre/lib/rt.jar 或 sun.boot.class.path 路径下的内容),是用原生代码来实现的(C++),并不继承自java.lang.ClassLoader
  • 扩展类加载器(Extension ClassLoader):用来加载Java的扩展库(JAVA_HOME/jre/lib/ext/*.jar或 java.ext.dirs 路径下的内容) .java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
  • 应用程序类加载器(Application ClassLoader):它根据 Java 应用的类路径(ClassPath, java.class.path)来加载。一般来说,Java应用的类都是由它来完成加载的。
  • 自定义类加载器:开发人员可以通过继承 java.lang.ClassLoader 类的方式实现自己的类加载器,以满足一些特殊的要求

6.什么是GC

当程序创建对象、数组等引用类型实体时,系统会在堆内存为其分配一块内存区,当这块内存不再被引用变量引用时,这块内存就变成了垃圾,等待垃圾回收机制回收。
垃圾回收机制有以下特点:

  • 只负责回收堆内存的对象,不回收任何物理资源(数据库连接,网络IO等资源)
  • 程序无法控制回收的时间。当对象永久性失去引用后,系统会在合适的时间回收它占用的内存。
  • 垃圾回收机制回收任何对象之前,都会调用该对象的finallize()方法,改方法可能使该对象复活(让对象重新获得引用),从而导致垃圾回收机制取消回收。

7.对象在内存中的状态(了解)

面试题—JVM_第3张图片

8.了解finalize()吗?

垃圾回收机制回收对象之前,会调用这个方法。它是Object的一个方法,可以重写,什么时候调用这个方法是不确定性的。

9.强制垃圾回收?

两种方法:

  • System.gc();
  • 调用Runtime对象的GC实例方法:Runtime.getRunTime.gc()

10.对象的引用类型

强引用:GC时不会被回收
软引用:描述有用但不是必须的对象,在发生内存溢出异常之前被回收
弱引用:描述有用但不是必须的对象,在下一次GC时被回收
虚引用(幽灵引用/幻影引用):如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

你可能感兴趣的:(面试题)