之前的面试中没有了解过JVM是什么。根据狂神以及二哥的面试内容,较为明确的了解了一下。至少明白了垃圾回收器的工作原理,以及整个JVM系统包括啥。如果这一块需要学习的话,建议还是根据上边两位前辈的内容详细的思考一下。
文章目录
JVM 位置
jvm位于操作系统之上,像一个软件,使用C实现,JRE,java运行环境中包含了jvm
jvm是什么?
Java虚拟机中的Java解释器负责将字节码文件解释成为特定的机器码进行运行,java虚拟机
JVM的体系结构
java程序的编译
1、源文件由编译器编译成字节码(ByteCode) 2、字节码由java虚拟机解释运行。因为java程序既要编译同时也要经过JVM的解释运行,所以说Java被称为半解释语言( “semi-interpreted” language)。
JVM体系结构
jvm的主要组成部分
类加载器(ClassLoader):加载Class文件
实例所处位置
加载器有多种,这里会根据查找,一层一层的向下查找。爷爷的爷爷是虚拟机自带的加载器
- 应用程序加载器
- 扩展类加载器
- 启动类加载器
- 虚拟机自带的加载器
运⾏时数据区(Runtime Data Area)
这里值得一提,每个线程都有程序计数器,线程私有。
方法区:静态变量,常量,构造方法,接口定义,运行时的常量池存在方法区中,但实例变量存在堆内存中和方法区无关。( static final Class模板 常量池)
栈:数据结构,先进后出。主管程序运行。在内存中把main先压进去,然后其他的再压进去。生命周期和线程同步。栈不存在垃圾回收,线程结束,栈就结束。
堆内存,是可以调节大小,类,方法,常量,变量,以及引用类型的真是对象
栈 堆 方法区的关系:
面试题 队列和栈是什么?有什么区别?
java中实例化对象在内存中的操作,这里可能有一些问题,对于方法区应不应该存在main与tell,但是只是作为class的模板存在。
执⾏引擎(Execution Engine):将java转成字节码以后,并不能直接给底层实现,需要此引擎转为底层指令。
本地库接⼝(Native Interface):这个过程中,如果调用其他语言,需要用本地接口库
面试题
双亲委派模型
明确一点与加载器有关系
目的:为了保证安全
解释:类加载器收到类加载的请求后,会逐层递进 APP(应用程序加载器)->EX(拓展类加载器)->启动类加载器。只有当父加载没办法完成加载请求时,转而去执行子加载器。
★:应用场景,比如我们写一个String 方法,而且与JDK里边的 包名都一样,手动写一个java.lang.String,但是本身java中有这样一个类,所以我们在执行中会一层一层向上找,找到的是手动写的java.lang.String。
面试题:类装载的执行过程
图可能有些问题,这里欢迎指正
沙箱安全机制
将java代码,限定在虚拟机的特定的运行环境中。在后续的一些版本中引用了域的概念。
组成沙箱的基本组件
- 字节码校验器:确保java类的内容是合规矩的,比如一个不加分号。
- 类加载器:运用双亲委派机制,实现防止恶意代码去干涉善意代码。引入域的概念。
使用Native 的原因
废话不说先上图。
本地方法接口英文:JNI :java native interface。扩展java的使用,融合不同的编程语言,为java使用。
在内存区域中,专门标记了一块位置,使用c与C++实现
实现场景:java调用本地。比如说打印机。本地管理系统
面试题:
面试题:
垃圾回收,详细讲一下堆
堆是可以调节大小,类,方法,常量,变量,以及引用类型的真是对象
堆内存要细分为:
- 新生区:
类诞生和成长死亡的地方。
整个垃圾的清理过程,假设十个人在新生区,经过第一次垃圾回收(轻GC)存活下来1个人。进入了幸存区,等到两个幸存区都满了,进养老区之前触发(重GC)。幸存两个区位置会来回互换。
每次GC都会将伊甸园区的对象移到幸存区,进入幸存区进行选择,谁空进谁。
- 养老区。
当一个对象经历了15次GC,就会进入养老区。15次是默认参数,这里也是可以调的。
- 永久区,在jdk8以后,变了个名字,元空间。
常驻内存,存放JDK自身携带的Class以及接口,和一些运行环境,这里不存在垃圾回收机制。只有当JVM关闭时
此时出现的问题:启动类重包含大量的第三方JAR包,tomcat包含太多的应用,以及大量动态生成的反射类,直到内存满,出现OOM
垃圾回收一般在新生区跟养老区
堆内存满了以后报错OOM,堆内存错误
以上的整个过程就是分代垃圾回收器的工作原理。
调节jvm内存
jvm内存初始化之前是占电脑内存的四分之一
jvm初始化内存占电脑内存的十六分之一
JVM调优参数
-Xms1024m -Xmx1024m -XX:+PrintGCDetails
//xms是设置初始化内存分配大小 xmx设置最大分配内存
//-XX:+PrintGCDetails 打印CG垃圾回收信息
//当我出现OOM的问题,把文件dump出来
-Xms1024m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError
//通过这个参数设定新生区的对象经过多少次进入老年区
-XX:MaxTenuringThreshold=9999.
-XX:+UseConcMarkSweepGC:指定使⽤ CMS + Serial Old 垃圾回收器组合;
研究OOM故障 面试题:JVM调优工具
能看到代码第几行出错,利用内存快照分析工具,MAT,Jprofiler
MAT,Jprofiler作用
- 分析Dump内存文件,快速定位内存泄漏
- 获取堆中数据
- 获取大的对象
软件下载安装
安装IJ的插件
下载:https://www.ej-technologies.com/download/jprofiler/files,桌面化工具
配置
编写出错问题
package com.xiucai;
import java.util.ArrayList;
public class test {
byte[] array=new byte[1024*114];
public static void main(String[] args) {
ArrayList<Object> list = new ArrayList<>();
System.out.println("hello");
try {
while (true){
list.add(new test());
}
}catch (Exception e){
System.out.println("测试");
}
}
}
出错了,此时需要Dump文件,用到了刚刚学的JVM内存调节
修改JVM内存
执行 jvm调节
-Xms1024m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError
再次执行,Dump出了文件。
在项目中找到
直到arrayList有问题
我们执行了main线程
GC :垃圾回收机制
作用区域:在方法区与堆
我们主要在堆的
两种类型,轻GC与重GC
标记清除法
标记,对所有活着的对象进行标记。
清除:对没有标记的对象,进行清除。
优点:两次扫描。浪费时间,会产生内存碎片
标记整理
或者叫标记压缩
对标记清除的一种优化,防止内存碎片产生
标记清除整理:先进行几轮标记清除,再进行整理会减少移动内存碎片产生的成本。
复制算法
针对的是幸存区,谁空把一个复制到另一个,让to保持干净。复制算法就是把这些内容复制过去。
好处:没有内存的碎片
坏处:浪费了内存空间
引用计数法
对堆中的对象,记录引用次数,引用次数为0时清出去。
由于大型项目比较多,所以不常用
面试题 .怎么判断对象是否可以被回收?
说一下JVM有哪些垃圾回收器
Serial:最早的单线程串行垃圾回收器
Serial Old:早期的瑟瑞,也是单线程的
ParNew(爬牛):是Serial的多线程版本。
Parallel 是多线程的,以吞吐量优先,牺牲时间换臀腿昂
★CMS:以活动最短停顿时间为目标,适用于B/S系统
CMS,全程Concurrent Mark-Sweep的简称,牺牲吞吐量获得最短停顿时间的垃圾回收器。
使用标记清除算法实现,会产生内存碎片,当内存不满足于条件是,会调用Serial Old进行垃圾回收。
新⽣代垃圾回收器和⽼⽣代垃圾回收器都有哪些?有什么区别?
新:Serial ParNew 一般采用复制算法 内存效率高,利用率低
老:Serial Old Parallel Old CMS 标记整理法。
总结
内存效率:复制算法>标记清除算法>标记压缩算法
内存整齐度:复制算法=标记压缩算法>标记清除算法
内存利用率:标记压缩算法=标记清除算法>复制算法
面试题 .java 中都有哪些引⽤类型?
JMM
Java Memory Model :java内存模型
作用:缓存一致性协议,定义数据读写的规则。定义了线程与主内存之间的抽象关系。
为了解决缓存一致性,这个缓存指的事cache区里边的缓存。
理解
java内存模型规定,所有变量都存储在主内存中,每条线程有自己的工作内存。此工作内存有主现成的副本,线程对于自己内存里边的更改数据变量以及一些内容,通过java内存模型来统一调配时间。
遇见的面试选择题
A:程序员不能够主动去操作释放内存
B:回收程序在这里指的是JC
C:程序员不能够主动去操作释放内存
D:程序员可以调用垃圾回收程序,但是不能指定时间