JVM学习笔记

1 JVN入门探究

  • 谈谈对JVM的理解?java8虚拟机和之前的变化更新?
  • OOM内存溢出,StackOverFlowError栈溢出,怎么分析?
  • JVM 的常用调优参数有哪些?
  • 内存快照如何抓取,怎么分析Dump文件?
  • 谈谈JVM中,类加载器你的认识?rt-jar ext applicatoin

2 JVM的体系研究

2.1 JVM位置

在这里插入图片描述

2.2 JVM的体系结构

在这里插入图片描述

  • 百分百没有垃圾(因为栈的运行方式,不存会在垃圾)
  • 所谓的 JVM 调优,99%都是在调方法区,其中主要的是
  • 第三方插件,主要是在执行引擎上做,类加载器上比较少

2. 类加载器

**作用:**加载Class文件

  • 类是抽象的,对象是具体的
  • 对象的引用地址在栈,具体数据在堆
  • 第三方插件,主要是在执行引擎上做,类加载器上比较少
    在这里插入图片描述

2.1 理解类加载器:

class Test{
    
public static int a = 1; 
}
//我们程序中给定的是 public static int a = 1; 

但是在加载过程中的步骤如下:

  1. 加载阶段 编译文件为 .class文件,然后通过类加载,加载到JVM
  2. 连接阶段
    第一步(验证):确保Class类文件没问题
    第二步(准备):先初始化为 a=0。(因为你int类型的初始值为0)
    第三步(解析):将引用转换为直接引用
  3. 初始化阶段: 通过此解析阶段,把1赋值为变量a
    输出都为同一个类:
public class Car {
   
  public static void main(String[] args) {
   
    Car car1 = new Car();
    Car car2 = new Car();
    Car car3 = new Car();
    Class<? extends Car> aClass = car1.getClass();
    Class<? extends Car> aClass1 = car2.getClass();
    Class<? extends Car> aClass2 = car3.getClass();
    System.out.println(aClass);
    System.out.println(aClass2);
    System.out.println(aClass2);

  }
}
Class Car

2.2 类加载器的执行顺序

类的加载指的是将类的.class文件中二进制数据读入到内存中,将其放在运行时数据区内的方法区内,然后再内存中创建一个 java.lang.Class 对象用来封装类在方法区内的数据结构。

  1. 对于静态字段来说,只有直接定义了该字段的类才会被初始化;
  2. 当一个类在初始化时,要求其父类全部都已经初始化完毕了;
  3. 所有Java虚拟机实现必须在每个类或者接口被Java程序“首次主动使用”时才初始化他们
public class Ltest {
   
  public static void main(String[] args) {
   
    System.out.println(Child.str2);
  }
}
  class MyParent{
   
    public  static String str1 = "hello";
    static {
   
      System.out.println("MyParent static");
    }
  }

  class Child extends MyParent{
   
    public static String str2 = "world";
    static {
   
      System.out.println("Child static");
    }
  }

输出:

MyParent static
Child static
world

2.3 常量池的概念

常量在编译阶段会存入到调用这个常量的方法所在的类的常量池中 本质上,调用类并没有直接用用到定义常量的类,因此并不会触发定义常量的类的初始化。 注意:这里指的是将常量存放到了MyTest2的常量池中,之后MyTest2与MyParent2就没有任何关系 了。

public class Ltest2 {
   
  public static void main(String[] args) {
   
    System.out.println(MyParent2.str3);
  }
}
class MyParent2{
   
  public static final String str3 = "qwe";
  static {
   
    System.out.println("MyParent2 static");
  }
}

qwe

当一个常量的值并非编译期间可以确定的,那么其值就不会被放到调用类的常量池中, 这是在程序运行时,会导致主动使用这个常量所在的类,显然就会导致这个类被初始化。

import java.util.UUID;

public class Ltest2 {
   
  public static void main(String[] args) {
   
    System.out.println(MyParent2.str3);
  }
}
class MyParent2{
   
  public static final String str3 = UUID.randomUUID().toString();
  static {
   
    System.out.println("MyParent2 static");
  }
}

因为这个例子的值,是只有当运行期才会被确定的值,所以需要运行static方法。而上一个例子的值,是编译时就能被确定的值。


                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值