大家好,又见面了,我是你们的朋友全栈君。
身边有同学实习面试被问,JVM性能调优等问题,来总结一下JVM
JDK1.8已经不存在方法区,增加了元空间;
如对象组成中的分代年龄(4bit),跟GC的分代相关;
什么是程序计数器,作用? 什么是 Java 虚拟机栈,作用? 什么是 本地方法栈,作用? 什么是 堆,作用? 什么是方法区,作用? 说出java文件运行的整个过程?
java类文件转换为class文件,在经过类装载系统,到达运行时数据区运行(我们常常说到的内存管理就是针对这段空间进行管理(如何分配和回收内存空间));运行时数据区包括(程序计数器,虚拟机栈,本地方法栈,堆(线程共享),方法区(线程共享)); Java虚拟机栈存放着许多栈帧,每个方法执行的同时都会创建一个栈帧(stack Frame),方法执行完成,出栈;整个过程可以看成在虚拟机栈的入栈出栈过程; 帧结构:1. 局部变量表,2. 操作数栈,3.动态链接,4.方法出口
发现java文件与对应字节码文件的关系
public int compute() {
#java文件
int a = 0;
int b = 1;
int c = (a + b) * 10;
return c;
}
public int compute(); #对应的字节码
Code:
0: iconst_0 #
1: istore_1
2: iconst_1
3: istore_2
4: iload_1
5: iload_2
6: iadd
7: bipush 10
9: imul
10: istore_3
11: iload_3
12: ireturn
GC是什么,工作方式和区域等?
public class GCtest {
//100kb
byte[] a = new byte[1024 * 100];
public static void main(String[] args) throws InterruptedException {
ArrayList<GCtest> gCtests = new ArrayList<>();
while (true) {
gCtests.add(new GCtest());
Thread.sleep(10);
}
}
}
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.gjf.GCtest.<init>(GCtest.java:13)
at com.gjf.GCtest.main(GCtest.java:17)
Arthas(阿尔萨斯)是阿里巴巴开源的 Java 诊断工具,深受开发者喜爱。
减少GC,特别是FullGC
是指使用单线程进行垃圾回收的回收器,每次回收只有一个工作线程(对并行能力比较弱的电脑,运行性能较好) 注意:串行回收器运行时,所有
应用程序的线程都停止工作,属于独占式的垃圾回收方式
; 线程进行等待的现象称为–>Stop-The-World,造成非常糟糕的用户体验;
多个线程同时进行垃圾回收,适合并行能力强的计算机;
关注吞吐量
,其中包括复制算法,标记压缩算法等回收算法注意:还是会造成线程等待现象–>Stop-The-World(STW),但是减少垃圾回收的停顿时间就会同时减小系统的吞吐量
CMS回收器主要关注
系统的停顿时间
,并发标记清除,是一个基于标记清除算法的回收器
; CMS掉工作过程相对复杂,不是独占式的回收器,工作过程中,应用程序仍然工作; 不会等到堆内存饱和后进行回收,而是到达一定阈值才开始垃圾回收 参数 说明 -XX:CMSInitiatingOccupancyFraction 默认堆老年代使用达到68%,执行CMS回收,如果在执行过程中内存不足,就会启动串行回收器进行垃圾回收,应用程序将完全中断; 根据此参数进行调优,增大阈值可以降低CMS的触发,减少老年代的回收次数;如果内存使用增长很快,应该降低阈值; CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的垃圾收集器。从名字可以看出,CMS 是基于标记-清除算法的。它的运作过程主要分为四个步骤:
Garbages First(G1)垃圾回收器,作为CMS的长久替代方案,使用了全新的分区算法;
eden区被占满,新生代GC启动,ednn区会被全部回收
,至少存在一个survivor区,老年代区域增大;
在并发标记后就知道哪个区域的垃圾较多,G1就会优先回收垃圾比例高的区域
-Xmx32m -Xms32m -XX:+UseSerialGC -XX:+PrintGCDetails
G1具备如下特点:
CMS 用于老年代的回收,而 G1 用于新生代和老年代的回收。
G1 使用了 Region 方式对堆内存进行了划分,且基于标记整理算法实现,整体减少了垃圾碎片的产生。CMS使用“标记-清理”算法会产生大量的空间碎片;
JVM调优很大程度上是对GC的调优,导出堆,对导出的dump文件进行分析,我们可以找到内存热点,可以找到哪个类型的对象数量最多,且占用的内存最多;哪个对象的体积大,还频繁被销毁创建; 但是JVM的调优本质实际上是通过JVM监控来分析JAVA代码的工作情况,找出不合理的设计和低质量的代码,进行改进;
-Xmx512m -XX:MaxPermSize=32M -Xloggc:gc:gc.log -XX:+PrintGCDetails\
//MaxPermSize为最大的永久区大小。
JVM中的内存区域一般分为3个部分: 年轻代、年老代和永久代;永久代在JDK 7中逐渐变化,到JDK 8之后完全消失,合并到了Native堆中,JDK8中,PermSize和MaxPermSize参数也一并移除了。
内存溢出(OOM)
待续,如何看问题做性能优化
程序计数器 内存空间小,线程私有。字节码解释器工作是就是通过改变这个计数器的值来选取下一条需要执行指令的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器完成 如果线程正在执行一个 Java 方法,这个计数器记录的是
正在执行的虚拟机字节码指令的地址
;如果正在执行的是 Native 方法,这个计数器的值则为 (Undefined)。此内存区域是唯一一个在 Java 虚拟机规范中没有规定任何 OutOfMemoryError 情况的区域
。线程私有
,生命周期和线程一致。描述的是 Java 方法执行的内存模型:每个方法在执行时都会床创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。 **局部变量表:**存放了编译期可知的各种基本类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型)和 returnAddress 类型(指向了一条字节码指令的地址),第一位放的是0,代表this当前对象; StackOverflowError:线程请求的栈深度大于虚拟机所允许的深度。 OutOfMemoryError:如果虚拟机栈可以动态扩展,而扩展时无法申请到足够的内存。 本地方法栈 区别于 Java 虚拟机栈的是,Java 虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则使用 Native 方法。也会有 StackOverflowError 和 OutOfMemoryError 异常。 Java 堆 对于绝大多数应用来说,这块区域是 JVM 所管理的内存中最大的一块。线程共享,主要是存放对象实例和数组。内部会划分出多个线程私有的分配缓冲区
(Thread Local Allocation Buffer, TLAB)。可以位于物理上不连续的空间,但是逻辑上要连续。(GC,G1主要工作区域) OutOfMemoryError:如果堆中没有内存完成实例分配,并且堆也无法再扩展时,抛出该异常。 方法区 属于共享内存区域
,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/132965.html原文链接:https://javaforall.cn