这里写目录标题
1.jvm是什么
java虚拟机,是实现java跨平台的核心组件。
2.jvm的作用
java中所有的类,必须被装载到jvm中才能使用,装载由类加载器完成,.class这个类型可以在虚拟机运行,但不是直接和操作系统交互,需要jvm解释给操作系统,解释的时候需要java类库,这样就能和操作系统交互。
3.java文件的加载过程
.java–》.class–》类加载器–》jvm
4.jdk、jre、jvm的区别
- JDK(Java SE Development Kit),Java标准开发包,它提供了编译、运行Java程序所需的各种工具和资源,包括Java编译器、Java运行时环境,以及常用的Java类库等。
- JRE(Java Runtime Environment),Java运行环境,用来运行Java的字节码文件。JRE中包括了JVM以及JVM工作所需要的类库,普通用户只需要安装JRE来运行Java程序,而程序开发者必须安装JDK来编译、调试程序。
- JVM(Java Virtual Machine),Java虚拟机,是JRE的一部分,它是整个Java实现跨平台的最核心的部分,负责运行字节码文件。
5.类加载器的作用
将Class文件字节码内容加载到内存中,并将这些静态数据转成方法区的运行时数据结构,然后在堆中生成一个代表整个类的Java.lang.Class对象,作为方法区中类数据的访问入口。
6.类加载器的类型
- 启动类加载器(Bootstrap Class Loader):引导类加载器,负责加载Java的核心类库,如JRE中的rt.jar(包含Java标准库)等。它是JVM内部的一部分,使用C++编写,是最顶层的类加载器,无法被Java代码直接引用或自定义。
- 扩展类加载器(Extension Class Loader):扩展类加载器,负责加载Java的扩展类库,如JRE中的ext目录下的Jar包。它是由Java语言编写的,是由启动类加载器加载的。
- 应用程序类加载器(Application Class Loader):系统类加载器,负责加载应用程序的类,包括用户自定义的类以及第三方类库。它是由Java语言编写的,是类加载器的默认类加载器,在Java应用程序中最常用的类加载器。
- 自定义类加载器(Custom Class Loader):用户自定义类加载器,是开发者根据需求自己编写的类加载器,可以通过继承java.lang.ClassLoader类来实现。自定义类加载器可以用于实现一些特定的类加载需求,例如加载加密的类文件、从非标准的位置加载类文件等。
7.双亲委派机制的加载过程
双亲委派机制是Java类加载器的一种工作模式。当一个Java类需要被加载时,Java虚拟机会先将加载请求传递给它的父类加载器,如果父类加载器无法找到该类,才会将加载请求传递给子类加载器。这个过程就像一个向上查找的层级结构,直到被找到或者抛出ClassNotFoundException异常。
8.双亲委派机制的优缺点
优点:保证类加载的安全性,避免重复加载,不管哪个类被加载,都会被委托给启动类加载器,只有父加载器不能加载,才会让子加载器加载,这样保证最后得到的对象都是同一个。
缺点:子加载器可以使用父加载器的类,而父加载器不能使用子加载器的类。
9.为什么要打破双亲委派机制
子加载器可以使用父加载器加载的类,而父加载器不能使用子加载器加载的类。
例如:使用JDBC连接数据库,需要用到com.mysql.jdbc.Driver和DriverManager类。然而DriverManager被启动类加载器所加载,而com.mysql.jdbc.Driver被应用程序加载器加载,使用启动类加载器加载不到,所以要打破双亲委派机制。
10.打破双亲委派机制的方式
- 自定义类加载器,重写loadclass方法。
- 使用线程上下文类(ServiceLoader:使父加载器可以加载子加载器的类)。
11.jvm的每个部分储存的都是什么
- 堆(线程共享):是虚拟机内存中最大的一块,储存的是实例对象和数组。
- 方法区(线程共享):常量池、静态(static)变量以及方法信息(方法名、返回值、参数、修饰符等)等。
- 本地方法栈(线程不共享):调用的本地方法,被native修饰的方法,java不能直接操作操作系统,所以需要native修饰的方法帮助,
- 虚拟机栈(线程不共享):八大基本类型、对象引用、实例方法。
- 程序计数器(线程不共享):每个线程启动都会创建一个程序计数器,保存的是正在执行的jvm指令,程序计数器总是指向下一条将被执行指令的地址。
12.内存溢出(oom)、内存泄漏和栈溢出
内存溢出的原因:①内存使用过多或者无法垃圾回收的内存过多,使运行需要的内存大于提供的内存。②长期持有某些资源并且不释放,从而使资源不能及时释放,也称为内存泄漏。
解决:①进行jvm调优。-Xmx:jvm最大内存。-Xms:启动初始内存。-Xmn:新生代大小。-Xss:每个虚拟机栈的大小。②使用专业工具测试。
手动制造:一直new对象就ok
栈溢出原因:线程请求的栈容量大于分配的栈容量。
解决:①修改代码②调优 -Xss
手动制作:一直调用实例方法。
内存泄漏(memroy leak)
严格来说,只有对象不会再被程序用到了,但是GC又不能回收它们的情况,才叫内存泄漏。
宽泛的讲,实际情况中很多时候一些不太好的实践会导致对象的生命周期变得很长甚至导致OOM,也叫“内存泄漏”。
申请了内存用完了不释放,如申请了1024M内存,分配了512M内存一直不回收,那么可用内存就只有512M,彷佛泄漏掉一部分。
13.垃圾回收的作用区域
GC垃圾回收的作用区域集中于堆和方法区。栈由于先进后出的特性,所有存在于栈中的方法或者变量等,最后都会出栈,因此栈中不存在可回收的垃圾。
14.怎么判断对象是否可回收
最重要的是判断这个对象是否还被使用,没有被使用就会被回收。
- 引用计数器:为每个对象增加一个引用计数器,当引用计数器为0的时候就进行回收。需要额外的空间存储引用计数器,实现比较简单、效率高。在处理一些复杂的循环引用或者相互依赖的情况下会造成内存泄漏。
- 可达性分析算法:首先确定一些肯定不能回收的对象作为GC Roots,以GC Root为起始节点向下去搜索直接或间接引用的对象,当遍历完成之后,有一些不可达的对象就是可回收的。是目前jvm主流的判断算法。
15.四种引用类型 强引用 软引用 弱引用 虚引用
- 强引用(Strong Reference):强引用是最常见的引用类型,在Java中默认的引用类型就是强引用。它是指在程序运行过程中,如果一个对象被一个强引用变量所引用,那么只要该变量还存在,垃圾收集器就不会回收这个对象。
- 软引用(Soft Reference):软引用用于描述一些还有用但不必须的对象。当JVM内存不足时,垃圾收集器会根据软引用的引用关系来判断是否回收这些对象。
- 弱引用(Weak Reference):弱引用是用于描述非必须对象的,只要该对象没有被任何强引用变量或软引用变量引用,即使存在弱引用变量,垃圾收集器也会回收这个对象。
- 虚引用(Phantom Reference):虚引用是最弱的一种引用类型,它只在被垃圾收集器回收时才会被使用。一个持有虚引用的对象,在任何时候都无法通过这个引用获得该对象的实例。可以使用虚引用监控对象的创建和销毁。
16.垃圾回收算法
- Mark-Sweep(标记-清除)算法:这是最鸡翅的垃圾回收算法,之所以说它是最基础的是因为它最容易实现,思想也是最简单的。标记-清除算法分为两个阶段:标记阶段和清除阶段。标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。
- Copying(复制)算法:为了解决Mark-Sweep算法的缺陷,Copying算法就被提了出来。它将可用内存按容易划分为大小相等的两块,每次只使用其中的一块。当着一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用的内存空间一次清理掉,这样一来就不容易出现内存碎片的问题。
- Mark-Compact(标记-整理)算法(压缩法):为了解决Copying算法的缺陷,充分利用内存空间,提出了Mark-Compact算法。该算法标记阶段和Mark-Sweep一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。