2021最新面试题-jvm篇
1、jvm是什么?
JVM就是JAVA虚拟机。是可运行 Java 代码的假想计算机 ,包括一套字节码指令集、一组寄存器、一个栈、 一个垃圾回收,堆 和 一个存储方法域。JVM 是运行在操作系统之上的,它与硬件没有直接 的交互。
2、JVM内存区域分类有哪些?
JVM 内存区域主要分为 线程私有区域【程序计数器、虚拟机栈、本地方法区】、线程共享区 域【JAVA 堆、方法区】、直接内存。
3、堆和栈的区别是什么?
完全是两个不同的东西
栈:
-XX:NewSize 新生代大小
8、什么是类加载器?
10、什么是双亲委派模型?
当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父 类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中, 只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的 Class),子类加载器才会尝试自己去加载。 采用双亲委派的一个好处是比如加载位于 rt.jar 包中的类 java.lang.Object,不管是哪个加载 器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载 器最终得到的都是同样一个 Object 对象。
11、为什么要打破双亲委派模型?
管程锁定规则:对一个锁的解锁操作,先行发生于后续对这个锁的加锁操作。这里必须强调的是同一个锁。
volatile 变量规则:对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。
线程启动规则:Thread 对象的 start() 方法先行发生于此线程的每一个动作。
线程 join() 规则:被调用 join() 方法的线程的所有操作先行发生于 join() 的返回。
传递性规则:操作 a 先发生于操作 b,操作 b 先发生于操作 c,则操作 a 先发生于操作 c。
ParNew 垃圾收集器(Serial+多线程)
Parallel Scavenge 收集器(多线程复制算法、高效)
Serial Old 收集器(单线程标记整理算法 )
Parallel Old 收集器(多线程标记整理算法)
CMS 收集器(多线程标记清除算法)
初始标记 只是标记一下 GC Roots 能直接关联的对象,速度很快,仍然需要暂停所有的工作线程。
并发标记 进行 GC Roots 跟踪的过程,和用户线程一起工作,不需要暂停工作线程。
重新标记 为了修正在并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记 记录,仍然需要暂停所有的工作线程。
并发清除 清除 GC Roots 不可达对象,和用户线程一起工作,不需要暂停工作线程。由于耗时最长的并 发标记和并发清除过程中,垃圾收集线程可以和用户现在一起并发工作,所以总体上来看 CMS 收集器的内存回收和用户线程是一起并发地执行。
G1 收集器
基于标记-整理算法,不产生内存碎片。
2、可以非常精确控制停顿时间,在不牺牲吞吐量前提下,实现低停顿垃圾回收。
3、
应用场景 | 说明 | 备注 | |
---|---|---|---|
jps | 查看系统的java进程 | 显示指定系统内所有HotSpot虚拟机进程。参数:-l:显示main方法的名称-v:显示虚拟机启动时的JVM参数(这个好用)-m:输出传递给main方法的参数 | jps并不能显示所有的java进程。这个原因暂时未知,比如对于自定义启动脚本的进程支持不大好 |
jstat | 从参数中也可以看到对域gc的监控比较充分。可以通过它来获取gc相关的信息 | 监控虚拟机的各种状态信息。参数如下:-class:统计class loader行为信息 -compile:统计编译行为信息 -gc:统计jdk gc时heap信息 -gccapacity:统计不同的generations(不知道怎么翻译好,包括新生区,老年区,permanent区)相应的heap容量情况 -gccause:统计gc的情况,(同-gcutil)和引起gc的事件 -gcnew:统计gc时,新生代的情况 -gcnewcapacity:统计gc时,新生代heap容量 -gcold:统计gc时,老年区的情况 -gcoldcapacity:统计gc时,老年区heap容量 -gcpermcapacity:统计gc时,permanent区heap容量 -gcutil:统计gc时,heap情况 | 使用过程中也发现和jps同样的问题。就是通过ps aux|grep java查看的进程,使用jstat执行时报:not found。好处是命令行显示。可以在远程服务器上执行。而有类似功能的如visual vm是图形界面,需要本地远程连接。 |
jinfo | 使用jps可以查看启动时的参数列表,但是如果想看未指定参数的默认值,就需要jinfo了 | 通过 -flag 参数 可以打印使指定的jvm flag参数值。通过 -sysprops 可以打印出系统参数通过 -flag name=value 可以修改一部分可以在运行时改变的虚拟机参数值 | 在测试环境比较常用,比如想知道当前jvm进程的启动参数和系统属性时用到。第三种方法个人用的比较少,没有在生成环境上用过,比较谨慎。 |
jmap | 一般用于内存溢出或者full fc很频繁时,需要定位jvm 的内存使用情况 | 生成堆转存信息(也就是heapdump)。jmap的作用不仅仅是获取dump文件,还可以查询finalize执行队列(什么东东),java堆和永久代信息,如空间使用率(貌似和jinfo重合了)和使用哪种gc。参数:-dump:[live,]format=b,file=<filename> 使用hprof二进制形式,输出jvm的heap内容到文件=. live子选项是可选的,假如指定live选项,那么只输出活的对象到文件. -heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况. -histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量. -permstat 打印classload和jvm heap长久层的信息. 包含每个classloader的名字,活泼性,地址,父classloader和加载的class数量. 另外,内部String的数量和占用内存数也会打印出来. -F 强迫.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效. | 其他可以生成dump的方式:1、配置-XX:HeapDumpOnOutOfMemoryError在内存溢出时自动生成dump2、执行Kill -3 |
jhat | 分析dump文件。不过一般不使用,因为功能简陋以及实际使用中并不会在服务器进行分析 | ||
jstack | 用于定位线程异常增多,死锁或者死循环导致cpu使用率暴增的情况 | 用于生成虚拟机当前时刻的线程快照。也就是theaddump。通过threadump可以看到各个线程的调用栈,就知道没有响应的线程在后台做什么。参数:-F:正常请求无法响应时强制输出线程栈-l:除堆栈外,显示关于锁的附加信息 | jmap和jstack都会到时阻塞,所以需要摘线上流量才能执行。也可以代买中通过Thread类的getAllStackTraces方法可以获取虚拟机中的所有StackTraceElement对象,从而获取线程栈信息 |
visual vm |
27、你们线上应用的JVM参数有哪些。
-server
-Xms6000M
-Xmx6000M
-Xmn500M
-XX:PermSize=500M
-XX:MaxPermSize=500M
-XX:SurvivorRatio=65536
-XX:MaxTenuringThreshold=0
-Xnoclassgc
-XX:+DisableExplicitGC
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=0
-XX:+CMSClassUnloadingEnabled
-XX:-CMSParallelRemarkEnabled
-XX:CMSInitiatingOccupancyFraction=90
-XX:SoftRefLRUPolicyMSPerMB=0
-XX:+PrintClassHistogram
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-Xloggc:log/gc.log
28、g1和cms区别,吞吐量优先和响应优先的垃圾收集器选择。
CMS收集器:一款以获取最短回收停顿时间为目标的收集器,是基于“标记-清除”算法实现的,分为4个步骤:初始标记、并发标记、重新标记、并发清除。
G1收集器:面向服务端应用的垃圾收集器,过程:初始标记;并发标记;最终标记;筛选回收。整体上看是“标记-整理”,局部看是“复制”,不会产生内存碎片。
吞吐量优先的并行收集器:以到达一定的吞吐量为目标,适用于科学技术和后台处理等。
响应时间优先的并发收集器:保证系统的响应时间,减少垃圾收集时的停顿时间。适用于应用服务器、电信领域等。