Java性能调优面试-2

1、JVM整体架构

2、JVM内存模型

1、类装载子系统将字节码文件【.class】装载到运行时数据区,即装载到方法区;

2、执行引擎负责执行

3、JVM内存模型分析

1、线程私有:线程栈、本地方法栈以及程序计数器。

       线程公有:堆、方法区【元空间】

2、一个方法对应一块栈帧内存区域,栈帧是存放在栈区间内部

     下图中main()先进栈,computer()后进栈。

3、栈帧内部包含:局部变量表、操作数栈、动态链接、方法出口

public class Math {

    public static final Integer CONSTANT = 666;

    public int compute(){ //一个方法对应一块栈帧内存区域
        int a = 1;
        int b = 2;
        int c = (a + b) * 10;
        return c;
    }

    public static void main(String[] args) {
        Math math = new Math();
        math.compute();
        Math math2 = new Math();
        math.compute();
        System.out.println("hello");
    }
}

4、生成类的字节码文件【javap -c Math.class > Math.txt】

操作数栈:变量值中转的内存区域。

   iconst_1:将int类型变量1压入操作数栈【即操作数栈中有一个值1】

   istore_1 :  将int类型值存入局部变量1【即局部变量表中有一个a=1】

   iconst_2:将int类型变量2压入操作数栈【即操作数栈中有一个值2】

   istore_2 :  将int类型值存入局部变量2【即局部变量表中有一个b=2】

   iload_1:从局部变量1中装载int类型值【即将局部变量表中a=1的1装载到操作数栈】

   iload_2:从局部变量2中装载int类型值【即将局部变量表中b=2的2装载到操作数栈】

   iadd:从操作数栈的栈顶弹出两个变量做加法,对结果压入操作数栈【3】

   bipush: 将一个8位带符号整数压入栈【将10压入操作数栈】

   imul: 从操作数栈的栈顶弹出两个变量做乘法,对结果压入操作数栈【30】

   istore_3:将int类型变量30压入操作数栈【即操作数栈中有一个值30】

   iload_3:将int类型值存入局部变量30【即局部变量表中有一个c=30】

   ireturn:

动态链接:在main方法中,math.compute()中compute属于静态符号,在程序执行中将符号转为指令码,进行执行。

              动态链接:在程序动态运行时,存储指令码的内存地址。

方法出口:compute()执行完后,执行main方法的位置。

程序计数器:保存下一条要执行指令的地址。

本地方法栈:private native void start0()

为什么存在本地方法栈?因为java是95年产生,之前一直是c,java为了与c语言交互,故通过本地方法,java执行c代码.dll。

现在跨语言交互:Thrift、http、微服务等。

命令:javap -c Math.class > Math.txt

Compiled from "Math.java"
public class effective.java.Math {
  public static final java.lang.Integer CONSTANT;

  public effective.java.Math();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public int compute();
    Code:
       0: iconst_1
       1: istore_1
       2: iconst_2
       3: istore_2
       4: iload_1
       5: iload_2
       6: iadd
       7: bipush        10
       9: imul
      10: istore_3
      11: iload_3
      12: ireturn

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class effective/java/Math
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #4                  // Method compute:()I
      12: pop
      13: return

  static {};
    Code:
       0: sipush        666
       3: invokestatic  #5                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       6: putstatic     #6                  // Field CONSTANT:Ljava/lang/Integer;
       9: return
}

命令:javap -v Math.class > Maths.txt

Classfile /Users/lihe/workspace/crane/target/classes/effective/java/Math.class
  Last modified 2021-1-17; size 759 bytes
  MD5 checksum 64696f7de671d6425ce394fda905f460
  Compiled from "Math.java"
public class effective.java.Math
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #7.#31         // java/lang/Object."<init>":()V
   #2 = Class              #32            // effective/java/Math
   #3 = Methodref          #2.#31         // effective/java/Math."<init>":()V
   #4 = Methodref          #2.#33         // effective/java/Math.compute:()I
   #5 = Methodref          #34.#35        // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #6 = Fieldref           #2.#36         // effective/java/Math.CONSTANT:Ljava/lang/Integer;
   #7 = Class              #37            // java/lang/Object
   #8 = Utf8               CONSTANT
   #9 = Utf8               Ljava/lang/Integer;
  #10 = Utf8               <init>
  #11 = Utf8               ()V
  #12 = Utf8               Code
  #13 = Utf8               LineNumberTable
  #14 = Utf8               LocalVariableTable
  #15 = Utf8               this
  #16 = Utf8               Leffective/java/Math;
  #17 = Utf8               compute
  #18 = Utf8               ()I
  #19 = Utf8               a
  #20 = Utf8               I
  #21 = Utf8               b
  #22 = Utf8               c
  #23 = Utf8               main
  #24 = Utf8               ([Ljava/lang/String;)V
  #25 = Utf8               args
  #26 = Utf8               [Ljava/lang/String;
  #27 = Utf8               math
  #28 = Utf8               <clinit>
  #29 = Utf8               SourceFile
  #30 = Utf8               Math.java
  #31 = NameAndType        #10:#11        // "<init>":()V
  #32 = Utf8               effective/java/Math
  #33 = NameAndType        #17:#18        // compute:()I
  #34 = Class              #38            // java/lang/Integer
  #35 = NameAndType        #39:#40        // valueOf:(I)Ljava/lang/Integer;
  #36 = NameAndType        #8:#9          // CONSTANT:Ljava/lang/Integer;
  #37 = Utf8               java/lang/Object
  #38 = Utf8               java/lang/Integer
  #39 = Utf8               valueOf
  #40 = Utf8               (I)Ljava/lang/Integer;
{
  public static final java.lang.Integer CONSTANT;
    descriptor: Ljava/lang/Integer;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL

  public effective.java.Math();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 9: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Leffective/java/Math;

  public int compute();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=1
         0: iconst_1
         1: istore_1
         2: iconst_2
         3: istore_2
         4: iload_1
         5: iload_2
         6: iadd
         7: bipush        10
         9: imul
        10: istore_3
        11: iload_3
        12: ireturn
      LineNumberTable:
        line 14: 0
        line 15: 2
        line 16: 4
        line 17: 11
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      13     0  this   Leffective/java/Math;
            2      11     1     a   I
            4       9     2     b   I
           11       2     3     c   I

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #2                  // class effective/java/Math
         3: dup
         4: invokespecial #3                  // Method "<init>":()V
         7: astore_1
         8: aload_1
         9: invokevirtual #4                  // Method compute:()I
        12: pop
        13: return
      LineNumberTable:
        line 21: 0
        line 22: 8
        line 23: 13
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      14     0  args   [Ljava/lang/String;
            8       6     1  math   Leffective/java/Math;

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: sipush        666
         3: invokestatic  #5                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         6: putstatic     #6                  // Field CONSTANT:Ljava/lang/Integer;
         9: return
      LineNumberTable:
        line 11: 0
}
SourceFile: "Math.java"

5、JVM各部分

1、栈与堆关系?栈中对象变量执行堆中具体new的对象。

2、方法区【元空间】包含常量、静态变量、类元信息

3、方法区与堆关系?是相互指向。方法区中的静态变量如果是一个对象会指向堆中的对象;对中对象会指向方法区中的类元信息。

 

3、堆中new 对象是Object

Object Header(对象头):对象头中有个头指针指向对象所属的类。

对象头中头指针作用:当Math msth = new Math();math.compute()时,执行compute()时,对象通过头指针找到对应的类信息,找到类中方法进行执行。

6、堆区间

1、new 出的对象存储在eden。空间分配 Eden【8/10】,From【1/10】,To【1/10】,老年代【1/3】

2、当主线程执行完成,即main()执行完,即mian()栈帧出栈,此时堆中对象还存在,需要GC

3、GC Roots根节点:类加载器、Thread、虚拟机栈的本地变量表、static成员、常量引用、本地方法栈的变量等。

4、对象头中含有分代年龄字段,

老年代对象:静态变量和数据库连接池。其中正常对象年龄达到15岁后自动放到老年代。

7、JVM调优工具--jvisualvm

1、Eden Space从0增长到最高处,代表EdenSpace区被对象占满,此时GCTime进行GC。此时Eden Space空从0开始。

2、当Eden Space满发生GC时,suvivor区存储活着的对象年龄+1,此时在Suvicor0和Suvivor1不断移动

3、当对象年龄=15时,对象会移动到老年代,故老年代时突然升高。

4、当old区满时,发生Full GC。如果次时老年代中的对象都有指针指向,都不是垃圾,则会导致old不会释放空间,则发生OOM

public class HelpTest {

    byte[] a = new byte[1024*100];

    public static void main(String[] args) throws InterruptedException {
        List<HelpTest> helpTests = new ArrayList<>();
        while(true){
            helpTests.add(new HelpTest());
            Thread.sleep(50);
        }
    }
}

5、JVM调优

1、调优目的:因为实际FullGC非常慢,期间有STW会导致程序卡住,性能下降。目的是1、减少FullGC发生次数;2、减少一次FullGC时间

2、JVM调优主要是调整下面两个指标:

停顿时间:垃圾收集器做垃圾回收中断应用执行的时间。-XX:MaxGCPauseMillis

吞吐量:垃圾收集的时间和总时间占比:1/(1+n),吞吐量为1-1/(1+n)。-XX:GCTimeRate

 

 

 

 

 

评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值