JVM面试题(史上最强、持续更新、吐血推荐)
文章很长,建议收藏起来慢慢读!疯狂创客圈总目录 语雀版 | 总目录 码云版| 总目录 博客园版 为您奉上珍贵的学习资源 :
- 《尼恩Java面试宝典》持续更新+ 史上最全 + 面试必备 2000页+ 面试必备 + 大厂必备 +涨薪必备
- 经典图书:《Java高并发核心编程(卷1)》 面试必备 + 大厂必备 +涨薪必备
- 经典图书:《Java高并发核心编程(卷2)》 面试必备 + 大厂必备 +涨薪必备
- 经典图书:《Netty Zookeeper Redis 高并发实战》 面试必备 + 大厂必备 +涨薪必备
- 经典图书:《SpringCloud Nginx高并发核心编程》 面试必备 + 大厂必备 +涨薪必备
- 资源宝库: Java 必备 百度网盘资源大合集 价值>10000元
推荐:Java面试宝典(持续更新 + 史上最全 + 面试必备)
Java面试宝典,32个最新pdf,含2000多页,不断更新、持续迭代
JAVA知识与技巧,关注与私信博主(学习)课件,源码,安装包,还有最新大厂面试资料等等等
史上最全 Java 面试题 32 专题 总目录
精心梳理、吐血推荐、史上最强、建议收藏 |
阿里、京东、美团、头条.... 随意挑、横着走!!! |
1、Java算法面试题(史上最强、持续更新、吐血推荐) |
2、Java基础面试题(史上最全、持续更新、吐血推荐) |
3、JVM面试题(史上最强、持续更新、吐血推荐) |
4、架构设计面试题 (史上最全、持续更新、吐血推荐) |
5、Spring面试题 专题 |
6、SpringMVC面试题 专题 |
7、SpringBoot - 面试题(史上最强、持续更新) |
8、Tomcat面试题 专题部分 |
9、网络协议面试题(史上最全、持续更新、吐血推荐) |
10、TCP/IP协议(图解+秒懂+史上最全) |
11、JUC并发包与容器 - 面试题(史上最强、持续更新) |
12、设计模式面试题 (史上最全、持续更新、吐血推荐) |
13、死锁面试题(史上最强、持续更新) |
15、Zookeeper 分布式锁 (图解+秒懂+史上最全) |
14、Redis 面试题 - 收藏版(史上最强、持续更新) |
16、Zookeeper 面试题(史上最强、持续更新) |
17、分布式事务面试题 (史上最全、持续更新、吐血推荐) |
18、一致性协议 (史上最全) |
19、Zab协议 (史上最全) |
20、Paxos 图解 (秒懂) |
21、raft 图解 (秒懂) |
26、消息队列、RabbitMQ、Kafka、RocketMQ面试题 (史上最全、持续更新) |
22、Linux面试题(史上最全、持续更新、吐血推荐) |
23、Mysql 面试题(史上最强、持续更新) |
24、SpringCloud 面试题 - 收藏版(史上最强、持续更新) |
25、Netty 面试题 (史上最强、持续更新) |
27、内存泄漏 内存溢出(史上最全) |
28、JVM 内存溢出 实战 (史上最全) |
29、多线程面试题(史上最全) |
30、HR面经:过五关斩六将后,小心阴沟翻船!(史上最全) |
31、Hash连环炮面试题(史上最全) |
32、大厂面试的基本流程和面试准备(阿里、腾讯、网易、京东、头条......) |
史上最全 Java 面试题:JVM 篇
社群交流的面试真题
面试真题1:元空间会产生内存溢出么?在什么情况下会产生内存溢出?
具体问题:元空间会产生内存溢出么?在什么情况下会产生内存溢出?。
java8 及以后的版本使用Metaspace来代替永久代,Metaspace是方法区在HotSpot中的实现,它与持久代最大区别在于,Metaspace并不在虚拟机内存中而是使用本地内存也就是在JDK8中,classe metadata(the virtual machines internal presentation of Java class),被存储在叫做Metaspace的native memory.
永久代(java 8 后被元空间Metaspace取代了)存放了以下信息:
- 虚拟机加载的类信息
- 常量池
- 静态变量
- 即时编译后的代码
出现问题原因
错误的主要原因, 是加载到内存中的 class 数量太多或者体积太大。
解决办法
增加 Metaspace 的大小
-XX:MaxMetaspaceSize=512m
代码演示
模拟Metaspace空间溢出,我们不断生成类往元空间灌,类占据的空间是会超过Metaspace指定的空间大小的
查看元空间大小
java -XX:+PrintFlagsInitial
设置配置 这里设置10m方便演示效果
-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
编写代码
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MetaspaceDemo {
static class OOM{}
public static void main(String[] args) {
int i = 0;//模拟计数多少次以后发生异常
try {
while (true){
i++;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOM.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o,args);
}
});
enhancer.create();
}
} catch (Throwable e) {
System.out.println("=================多少次后发生异常:"+i);
e.printStackTrace();
}
}
}
运行结果:
正式内容1:Java内存区域
解释 Java 堆空间及 GC?
当通过 Java 命令启动 Java 进程的时候,会为它分配内存。内存的一部分用于创建堆空间,当程序中创建对象的时候,就从对空间中分配内存。GC 是 JVM 内部的一个进程,回收无效对象的内存用于将来的分配。
说一下 JVM 的主要组成部分及其作用?
JVM包含两个子系统和两个组件,两个子系统为Class loader(类装载)、Execution engine(执行引擎);两个组件为Runtime data area(运行时数据区)、Native Interface(本地接口)。
- Class loader(类装载):根据给定的全限定名类名(如:java.lang.Object)来装载class文件到Runtime data area中的method area。
- Execution engine(执行引擎):执行classes中的指令。
- Native Interface(本地接口):与native libraries交互,是其它编程语言交互的接口。
- Runtime data area(运行时数据区域):这就是我们常说的JVM的内存。
作用 :首先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader)再把字节码加载到内存中,将其放在运行时数据区(Runtime data area)的方法区内,而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。
下面是Java程序运行机制详细说明
Java程序运行机制步骤
- 首先利用IDE集成开发工具编写Java源代码,源文件的后缀为.java;
- 再利用编译器(javac命令)将源代码编译成字节码文件,字节码文件的后缀名为.class;
- 运行字节码的工作是由解释器(java命令)来完成的。
从上图可以看,java文件通过编译器变成了.class文件,接下来类加载器又将这些.class文件加载到JVM中。
其实可以一句话来解释:类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Class对象,用来封装类在方法区内的数据结构。
说一下 JVM 运行时数据区? 或者:说一下JVM内存模型?
思路: 给面试官画一下JVM内存模型图,并描述每个模块的定义,作用,以及可能会存在的问题,如栈溢出等。
Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存区域划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有些区域随着虚拟机进程的启动而存在,有些区域则是依赖线程的启动和结束而建立和销毁。Java 虚拟机所管理的内存被划分为如下几个区域:
- 程序计数器(Program Counter Register):当前线程所执行的字节码的行号指示器,字节码解析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能,都需要依赖这个计数器来完成;
- Java 虚拟机栈(Java Virtual Machine Stacks):用于存储局部变量表、操作数栈、动态链接、方法出口等信息;
- 本地方法栈(Native Method Stack):与虚拟机栈的作用是一样的,只不过虚拟机栈是服务 Java 方法的,而本地方法栈是为虚拟机调用 Native 方法服务的;
- Java 堆(Java Heap):Java 虚拟机中内存最大的一块,是被所有线程共享的,几乎所有的对象实例都在这里分配内存;
- 方法区(Methed Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。
深拷贝和浅拷贝
浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址,
深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存,
使用深拷贝的情况下,释放内存的时候不会因为出现浅拷贝时释放同一个内存的错误。
浅复制:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。
深复制:在计算机中开辟一块新的内存地址用于存放复制的对象。
说一下堆栈的区别?
物理地址
堆的物理地址分配对对象是不连续的。因此性能慢些。在GC的时候也要考虑到不连续的分配,所以有各种算法。比如,标记-消除,复制,标记-压缩,分代(即新生代使用复制算法,老年代使用标记——压缩)
栈使用的是数据结构中的栈,先进后出的原则,物理地址分配是连续的。所以性能快。
内存分别
堆因为是不连续的,所以分配的内存是在运行期确认的,因此大小不固定。一般堆大小远远大于栈。
栈是连续的,所以分配的