JVM基础面试知识点

本文详细解释了JVM的关键参数,如堆空间设置、新生代与老年代比例、垃圾回收策略等,介绍了常用的JDK工具如jinfo、jstat、jmap等,以及如何通过这些工具监控和优化内存使用。重点讲解了垃圾回收器的工作原理和JVM调优技巧,包括减少垃圾回收次数和理解逃逸分析等概念。
摘要由CSDN通过智能技术生成

JVM参数和查看本机默认参数

-Xms: 设置堆的最小空间大小。

-Xmx: 设置堆的最大空间大小。

-Xmn: 设置新生代最大内存大小(比列也有冲突的话,以这个为准--显式指出)。

-XX:NewRatio: 设置新生代与老年代的比例,默认是2。

-XX:SurvivorRatio: 设置新生代中Eden区于Survivor区的比例。

-XX:-UseAdaptiveSizePolicy: 关闭自适应的内存分配策略(+是开启,-是关闭)。

-XX:NewSize: 设置新生代最小空间大小。

-XX:MaxNewSize: 设置新生代最大空间大小。

-XX:MaxTenuringThreshold=<N>: 设置新生代幸存者1区或2区晋升到老年代(原空间)的年龄计数器阈值--默认15。

-XX:UseTLAB: 默认开启TLAB空间,-XX:TLABWasteTargetPercent设置TLAB占用Eden的百分比。

-XX:+DoEscapeAnalysis: 显示开启逃逸分析。

-XX:+PrintEscapeAnalysis: 查看逃逸分析的筛选结果。

-XX:+EliminateAllocations: 开启代码优化之标量替换。

-XX:PermSize: 设置永久代最小空间大小。

-XX:MaxPermSize: 设置永久代最大空间大小。

-Xss: 设置每个线程的堆栈大小。

windows--cmd命令:

jps: 列出当前正在运行的Java进程的进程ID和主类名称

jinfo -flag NewRatio 12088: 获取指定Java进程的 NewRatio (设置新生代和老年代的比例一半默认为2)参数值的命令

jstat -gc 10716: 是一个用于监视指定Java进程的垃圾回收统计信息的命令,或者通过jvisualvm进行可视化监控(需下载GC插件)

新生代(S0、S1)、Eden空间(EC)、老年代(OC)、元数据空间(MC)等的容量和使用情况,以及年轻代垃圾回收次数(YGC)和时间(YGCT)、Full GC 次数(FGC)和时间(FGCT)等

JVM常用调优工具

  • JDK:jinfo,jstat,javap,jmap荡下文件导入到Memeory Analyzer Tool分析

  • Jconsole,jvisualvm(jdk自带),Jprofiler(idea下载插件)

    jps (JVM Process Status): 类似 UNIX 的 ps 命令。用于查看所有 Java 进程的启动类、传入参数和 Java 虚拟机参数等信息;

    jstat(JVM Statistics Monitoring Tool): 用于收集 HotSpot 虚拟机各方面的运行数据;

    jinfo (Configuration Info for Java) : Configuration Info for Java,显示虚拟机配置信息;

    jmap (Memory Map for Java) : 生成堆转储快照;

    jhat (JVM Heap Dump Browser) : 用于分析 heapdump 文件,它会建立一个 HTTP/HTML 服务器,让用户可以在浏览器上查看分析结果;

    jstack (Stack Trace for Java) : 生成虚拟机当前时刻的线程快照,线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合。

垃圾回收器知识点

频繁在新生代回收,很少在老年代回收,几乎不在永久代/元空间收集!!

pivGwZR.png

Eden区放不下执行YGC,YGC会顺带执行幸存者区的垃圾回收,如果幸存者区还放不下就直接晋升为老年代,如果老年代放不下,执行Full GC或者Major GC

当Eden区满的时候出发YGC或者Minor GC顺带回收幸存者区的垃圾,达到一定条件晋升

幸存者1区和2区采用垃圾回收算法:1:1复制算法,解决碎片化问题 == 复制之后有交换,谁空谁是to ==

基于HotSpot VM的实现:部分收集器(Partial GC),整堆收集器(Full GC),STW:暂停用户线程,需要等待

Minor GC:Eden满的时候触发,Survivor满不会触发,GC整个年轻代。特点:朝生夕灭,频繁,速度快

Major GC:老年代空间不足时先触发Minor GC,再触发Major GC,之后内存还不足就OOM了

Full GC:调用System.gc()时--不必然,老年代不足,方法区不足,Minor GC后平均大小大于Old可用内存,开发中尽量避免

很多时候,Major GC会和Full GC混合使用!--G1 GC

JVM调优

减少垃圾回收的次数(减少用户的STW等待时间),重点是fullGC和majorGC--是minor GC的10倍以上

JVM面试知识点

TLAB:Thread Local Allocation Buffer:Eden区内开辟--每个线程分配一个私有缓冲区。(堆空间都是共享的吗?X-->还有线程私有的TLAB)

堆是对象内存分配的唯一选择吗?

代码优化方面:实际上是字节码文件加载到内存中以后,才执行优化。字节码还存在代码

  • 让对象在堆内的分配少一些(TaoBaoVM),生命周期较长的对象分配到栈上--栈上分配--避免堆上的垃圾回收

栈上分配要经过逃逸分析:一个对象并没有逃逸出方法的话,那么可能被优化成栈上分配了。new的一个对象只在方法内部使用

举例--return sb(逃逸);--return sb.toString()(不逃逸,在内部把StringBuffer使用了,没有发生逃逸);

理解:new的对象实体可能在方法外调用,开发中能使用局部变量的尽量避免在方法外定义

  • 同步省略:同步(synchronize)只能被一个线程访问,一个对象但是在方法内部,加同步没有意义,所以JIT编译器会同步消除掉。

  • 分离对象或标量替换:经过逃逸分析后,发现定义的标量(栈中栈帧的局部变量中)把定义的对象拆解成若干个成员变量来替换。

  • 方法区:字符串常量池,其中存在数量值,字符串值,属性引用,方法引用,符号引用(加载的父类,print Stream等 #54,#55,就是各种调相关常量池中的调用)

    • 方法区中主要进行垃圾回收的两部分内容:常量池中废弃的常量(没有没直接引用)和不在使用的类型。

    • static修饰会在编译阶段加载,初始化值会在连接的准备阶段,static final则会在编译阶段加载和初始化值。

    • 运行时常量池具备动态性:例如String的intern()方法会在常量池中校验有没有,没有的会加载到字符串常量池中

  • 对象实例化的几种方式:

pivGaL9.png

1. new:最常见的方式,变形1:单例模式下调用Xxx的静态方法(可见的无参构造方法)变形2:工厂模式XxxBuilder/XxxFactory的静态方法。
2. Class的newInstance():反射的方式,因为比较苛刻-只能调用空参的构造器,权限是public,在jdk1.9之后废除。
3. Constructor的newInstance(Xxx):反射的方式,可以调用空参、带参的构造器,权限没有要求。
4. 使用clone():不调用任何构造器,当前类实现Cloneable接口,实现clone方法。
5. 使用反序列化:从文件中、网络中获取一个对象的二进制流,可以反序列化一个对象。
6. 第三方库Objenesis

  • StringTable(字符串常量池):为什么会调整?元空间-->堆空间,触发永久代的回收效率很低,多数情况下是OLD区空间不足或永久代不足的Full GC 导致大量的字符串创建,回收效率低,永久代内存不足。

  • StringTable:涉及到的面试常用点

    • String的基本特性:字符串," "引起来,声明为final,不可被继承(已经很完备了),char数组转byte数组,节省空间

    • String的不可变性:字符串常量池中是不会存储相同内容的字符串的

String str1 = "javaEE";
String str2 = "hadoop";
String str3 = "javaEEhadoop";//都是常量的话直接编译器会优化,最终引用地址指向同一个字符串常量
String str4 = str1+"hadoop" / "javaEE"+str2 / str1+str2;
只要拼接符号的前后出现变量,则相当于在堆空间中new一个对象(开辟了一个新的空间,引用一个新的地址)
    
str1+str2执行的细节:(注意!!变量拼接才会这样,如果用final修饰(变量就不是变量--是常量了),常量的引用也会被编译器优化)
①StringBuilder s = new StringBuilder();
②s.append("a");
③s.append("b");
④s.toString() --->  约等于new String("ab");

  • new String()到底创建了几个对象:两个对象--一个对象是:new关键字在堆空间创建的,另一个对象是:字符串常量池中的对象。字节码指令:ldc

pivGNM4.jpg

pivGUsJ.jpg

⭐重点记忆⭐Java源程序经过编译后生成字节码文件,字节码文件通过类的加载器加载到运行时数据区,针对于字节码文件中的数据我们就会有一个具体的分配,针对于类信息本身存放在方法区中,针对于字节码文件执行的过程中,比如new对象了(在堆空间中),方法的调用的时候,在虚拟机栈中分配一个个的栈帧,在整个执行过程中也会用到方法计数器来计数(来记录整个线程当中代码执行到哪一行了),主要在方法区中放的是类信息,运行时常量池(字符串常量)

线程私有的:PC程序计数器、本地方法栈、虚拟机栈。

虚拟机栈中的每个栈帧又分为返回值,本地局部变量表,操作数栈,动态链接(执行运行时常量池中的方法引用,哪个具体的方法)

方法区中的常见垃圾回收:常量池中废弃的常量和不在使用的类型。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值