java面试知识总结--jvm相关(模型部分)

目标

为啥面试总爱问jvm的内存结构呢?更有甚者,还直接jmm,拽英文啊?实际工作又很少用到,凭啥总问我会不会呢?不过你问了,这里我就先来答下,哈哈。
本节主要内容,了解jvm内存模型,类加载,线程模型

内存模型

我喜欢按图说话:


jvm.jpg

分析下:

  1. java文件,通过java源码编译器我被翻译层class形式
  2. 我变成class形式后,包含三部分
    • 结构信息:我的版本、各部分数量大小
    • 元数据:常量、方法名、类信息等
    • 方法信息: 语句、表达式、字节码、值栈信息
      这时候我就等待java进程工作时来找我了.

可以通过javap -c看下内容

public class HelloWorld extends BaseResponseDTO {

    private static final int _1M = 1024 * 1024;

    private   volatile Integer integer=2;

    private  Boolean t=true;

    public static void main(String[] args) throws InterruptedException {

        HelloWorld H=new HelloWorld();
        H.integer=+1;
        H.t=false;
    }
}

对应的class文件内容如下

public class com.yeepay.power.common.aop.HelloWorld extends com.yeepay.power.common.dto.BaseResponseDTO {
  public com.yeepay.power.common.aop.HelloWorld();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method com/yeepay/power/common/dto/BaseResponseDTO."":()V
       4: aload_0
       5: iconst_2
       6: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       9: putfield      #3                  // Field integer:Ljava/lang/Integer;
      12: aload_0
      13: iconst_1
      14: invokestatic  #4                  // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
      17: putfield      #5                  // Field t:Ljava/lang/Boolean;
      20: return

  public static void main(java.lang.String[]) throws java.lang.InterruptedException;
    Code:
       0: new           #6                  // class com/yeepay/power/common/aop/HelloWorld
       3: dup
       4: invokespecial #7                  // Method "":()V
       7: astore_1
       8: aload_1
       9: iconst_1
      10: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      13: putfield      #3                  // Field integer:Ljava/lang/Integer;
      16: aload_1
      17: iconst_0
      18: invokestatic  #4                  // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
      21: putfield      #5                  // Field t:Ljava/lang/Boolean;
      24: return
}
  1. java进行开始执行,首先bootstrap先加载java等核心jar包,然后是ExtensionClassLoder加载java需要的扩展包,最后appClassLoader来加载刚才生成的class文件
    这里有个概念叫做双亲委派模型
    双亲委派模型工作过程是:如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载。
  1. 加载完所有class,我的服务也起来了,这个时候,有用户开始访问我了.这时候又涉及到了jmm模型问题,看我的图中可以看出,我所创建的类信息、对象数据等都存在jvm的主内存中(当然jdk8中元数据是放到系统内存中的),我在处理用户数据时,首先要申请一个线程,让一个线程来处理用户工作.

  2. 我就是那个线程,我的工作生活是这样子的(可参考文章https://mp.weixin.qq.com/s/dAHaWLiqjkuc8UpoeF6e5A,写的不错),我要工作,所以我向jvm申请了1m的工作空间(工作内存,可通过-xss配置),看下我的日常工作流:

    线程工作流

哈哈,我是有家的孩子,我的寿命很长哦!

  1. 对于我的工作空间,是这样子的:


    图片来源网络

线程的working memory只是cpu的寄存器和高速缓存的抽象描述.cpu在计算的时候,并不总是从内存读取数据,它的数据读取顺序优先级 是:寄存器-高速缓存-内存。线程耗费的是CPU,线程计算的时候,原始的数据来自内存,在计算过程中,有些数据可能被频繁读取,这些数据被存储在寄存器 和高速缓存中,当线程计算完后,这些缓存的数据在适当的时候应该写回内存。

所以java内存模型分为主内存,和工作内存。主内存是所有的线程所共享的,工作内存是每个线程自己有一个,不是共享的。

每条线程还有自己的工作内存,线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝。线程对变量的所有操作(读取、赋值),都必须在工作内存中进行,而不能直接读写主内存中的变量。不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成,线程、主内存、工作内存三者之间的交互关系如下图:

图片来源网络

每个线程通过JLS定义的八个对主存的操作指令:lock,unlock,read,load,use,assign,store,write。这些行为是不可分解的原子操作

参考资料:
https://www.cnblogs.com/wade-luffy/p/6051384.html
https://www.cnblogs.com/wxd0108/p/5479442.html
https://www.cnblogs.com/chihirotan/p/6486436.html

你可能感兴趣的:(java面试知识总结--jvm相关(模型部分))