JVM-Java-HotSpot

带你从新认识JVM

在这里插入图片描述

1.JVM运行时数据区

在这里插入图片描述 1.java虚拟机协议规定里面要有方法区和堆内存所以就有线程共享区
2.区分的意义就是线程是否安全
3.因为是线程共享的,所以所有的线程就能对其进行并发的修改
4.线程安全问题是对资源的竞争,包括进程外的资源
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
1.静态字段、方法在堆内存中不需要存储。
2.行为在堆里面,状态在堆里面。
★★★思考2.对象何时被回收?
在这里插入图片描述
1.引用计数器算法,存在两个对象相互引用的问题
2.对象里面有一个对象头,对象头里面有一个count值,count值初始值为0,有一个对象
引用它就+1,如果为0就回收掉。
3.对象互相引用导致对象的无法回收从而导致内存的泄露。
在这里插入图片描述
1.多个线程可以访问的存储数据不安全
2.java和线程的关系:java线程其实就是一段Java代码流到cpu中去执行(代码流一般就是一个方法)
3.栈先进后出的逻辑(方法调用的先进后出)
在这里插入图片描述
方法区的作用:通过动态引用,就能从方法区中找到方法。
在这里插入图片描述
在这里插入图片描述
“=”号就是返回值地址,返回值地址告诉我应该返回到上一个栈帧的什么地方。(栈帧也是一个内存区域)
在这里插入图片描述

2.JAVA类结构

在这里插入图片描述
1.(内存的运作过程)基本的铺垫:
JAVA代码要在JVM中执行,首先要编译成JAVA字节码文件(.class文件(一个方法被编译之后方法里面的代码会变成二进制字节码指令))。
2.JVM用另外一套字节码指令把方法里面的代码做了一个保存,每个指令都是一个16进制数,16进制数通过一个编码表把它表示成一个有意义的指令。
3.第一个指令是说将我们的值放到操作数栈,第二个指令是说将值放到局部变量表

3.图解JAVA程序运行过程

1.方法区、堆内存、线程独占内存区域它们都是静态的。
2.执行一段代码要在Java进程里执行,java进程里面有java线程共享内存区域(分为方法区(方法区用来存储类的原信息,也就是类对象)和堆内存)
3.这些代码会被编译成字节码指令,执行的话要启动一个线程(就是我们的一个主线程,main线程),启动一个线程就要为它分配一个独占的内存区域(独占的内存区域代表一个线程),独占线程区域就会有一个程序计数器和一个虚拟机栈(虚拟机栈就是方法接近后期描述调用的一个栈)。现在我们要执行main方法了,main方法对应的栈帧就是入栈,入栈之后栈帧里面有局部变量表(用来存储局部变量)和操作数栈和其它栈帧信息。
4.操作数栈和局部变量表怎么执行一串代码:
①命令一:将500这个值放在操作数栈,放在操作数栈之后会执行指令istore_1,
在这里插入图片描述
②命令二:istore_1赋值,将操作数栈栈里的元素出栈,放到局部变量表当中的第一个变量当中去
※在JVM中执行的时候一定不会X这个变量的名称,只会有“1”这个变量,“1”这个变量就代表了代码中的X变量
3.第二行代码同第一行,接下来执行除法操作,代码中的XY来自内存中的局部变量表中的“1”、“2”
在这里插入图片描述
③要执行除法操作,必须要把“1”、“2”放到操作数栈里,执行iload_1将第一个元素加载到操作数栈栈底,执行iload_2将第二个元素加载到操作数栈栈底。
在这里插入图片描述
④接下来就做(idiv指令)除法的操作,将操作数栈栈底的两个值出栈,出栈完后得到的值是5,然后就将得到的结果放回操作数栈。在这里插入图片描述
⑤除法的操作完了,接下来就做赋值操作,赋值就是将操作数栈栈底的元素放到局部变量表,所以执行指令istore_3 ,接下来整个的过程就完了
在这里插入图片描述
1.程序计数器:帮我们记录cpu执行字节码指令执行到哪里去了
2.操作数栈:信息存放器,用什么存什么
3.局部变量就是我们所说的栈
4.动态引用帮助在方法区里找到相关的代码
5.本地方法用来执行Native方法
6.本地方法栈执行的不是Java代码
7.class字节码文件前四个是一个文件头
https://study.163.com/(课时26)

JVM探究

1.JVM的指令手册

链接: https://pan.baidu.com/s/1oipDFI7L1YEDeflPuOx2Zg 密码: t32z

2.JVM详解

JDK体系结构
1.JDK包含JRE和java命令,JRE包含JDK和类库
2.JRE是运行时环境
在这里插入图片描述
1.java代码一个非常重要的特点:一次编写,多次运行。
2.操作系统最底层的代码时0101。
3.字节码文件->通过Java命令->通过不同系统的JVM(JDK系统版本不同)帮不同的系统编译成不同的机器码。
在这里插入图片描述
1.java字节码由类装载子系统加载到内存区里的方法区,然后由字节码执行引擎执行相关的代码。
2.完成Java虚拟机的三块组成
①类装载子系统(主要负责加载我们的字节码文件,加载到我们对应的内存区里面)
②运行时数据区
③字节码执行引擎去执行字节码文件
3.栈:存放局部变量
4.栈帧:不同的方法都有自己独立的一个栈内存区,栈帧它也是一块内存区
5.方法执行完马上就会出栈,就会别销毁掉
6.如果是多线程:Java虚拟机都会给线程分配一个独立的栈(栈内存区),这个栈是每一个线程独享的
7.分析java代码底层的字节码:
①字节码文件路径:D>ideaProjects>project-all>target>classes>com>tuling>jvm(字节码文件,.class文件(16进制代码))
②有更加可读的字节码,IDEA打开,项目->target->classes->com->concurre->jvm->Oper in Terminal(字节码文件,.class文件(16进制代码))->javap -(里面有个“-c”的参数,对代码进行反汇编,生成更可读的字节码(javap -c Math.class >),把它添加到一个记事本文件(javap -c Math.txt >),记事本文件里面就是Math文件的JVM指令)
8.程序计数器:程序计数器放我们线程马上要执行的下一行或这是正在执行的那一行。(记录执行到的代码行行号(或内存地址))
9.web应用程序–>多线程
10.每执行完一行指令,Java执行引擎每次都会对程序计数器做一个更新(程序计数器从第一行代码的时候就开始工作了)
11.操作数栈:程序运行时中转的一个内存区
12.先在局部变量表里分配一块内存区,然后在把值放进去
13.方法出口:当程序执行完方法之后 方法出口就告诉程序返回到main()方法执行时的那一行代码去(个方法一)。
14.main()方法也是有局部变量的,main()方法的局部变量不再是我们的基本类型,是一个对象类型
15.每一个new出来的对象的对象头都会指向所对应的类(new这个对象的时候,这个对象头存储了所属类的信息)
16.对象.方法中的方法其实是一个动态的符号,其实它是一个静态的符号,当你在运行的时候把这个符号转变为当前的代码(指令码),指令码的内存地址就是动态链接
17.动态链接这个指令码一定是再程序运行的时候动态生成的地址
18.动态链接:就是在程序运行的过程中,就像这个comnute()方法,它实际上是一个静态的符号;在程序运作的过程中,把这个符号转换为直接的代码(指令码)。这个方法的地址对应相关代码的指令码(这个方法在运行的过程中可以找到相关的指令码),这个指令码其实是被加载到方法区,加载到方法区也是有相关的内存地址,在程序运行的过程中,comnute()方法可以通过指针找到指令码的内存地址,这个内存地址实际上就是我们说的动态链接,这个地址就存储到我们的动态链接里(这个指令码一定是在程序运行过程中生成的地址)
19.更复杂的指令码,把7.②里的javap -c Math.class 改为 javap -v Math.class
20.系统运行-》把程序加载到方法区->每个方法都有内存地址存放在方法区->根据(堆里面)头指针找到我们子密码的内存地址->把地址放到动态链接这个区里面->当执行computer()方法的时候,就会通过动态链接的地址找到我们的子密码。
21.堆和方法区的联系:堆里有些对象头的指针指向我们的方法区的一些字节码(原信息)
22.本地方法栈:
①java里的本地方法:native方法,C语言写的 ,当程序运行到这一行代码的时候,它会去你操作系统的C语言实现的函数库,去找一个叫XX.dll文件,这个XX.dll文件里就有start0的实现。
②java语言要与C语言做交互就要用本地方法(现在其一种),本地方法里需要分配的内存就是我们的本地方法栈
③每个线程应该要有自己的本地方法栈
23.堆:
①minor gc==>执行引擎做的事情
②没有引用的就会清理
③GC Roots根
④轮转超过15次(老不死)的对象就放到老年代
⑤静态对象:静态变量不是存储在方法区的,但是它存储的是这个对象的指针
⑥老年代的对象满了之后,它会出发我们的full gc,full gc来释放我们的老年代对象,如果发现老年代的对象都有用,无法释放,就会报错,内存溢出

3.JVM-java虚拟机调优

java虚拟机调优目的:(提高性能)
尽量的减少full gc出现的次数,减少一次full gc出现的时间。(full gc出现的时间越长,卡死的时间越长)

GC调优步骤:(观察它的调优日志)
1、打印GC日志
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:./gc.log
Tomcat则直接加在JAVA_OPTS变量里
2、分析日志得到关键性指标
3、分析GC原因,调优JVM参数

4.JMM内存模型

多并发缓存架构图:
在这里插入图片描述
如果这个是双核笔记本:所有程序都在硬盘->我们运行程序->CPU会把我们的硬盘的数据加载到我们的主内存->(这么多年来我们主内存的存储速度和运算速度实际上是没什么变化的,CPU太快,主内存太慢,所以现在我们会在CPU和主内存中间加一个缓存,叫CPU高速缓存或者叫CPU寄存器。严格意义上来说这个CPU高速缓存在CPU内部,因为CPU的高速缓存是非常贵的,所以它的容量不是很大。CPU高速缓存的作用:解决CPU跟主内存之间数据的存储、读取、运算速度等一切问题)->在把我们的数据从主内存加载到CPU高速缓存里去(CPU在对数据做运算、存储的时候实际上是跟我们的CPU高速缓存做交互)
在这里插入图片描述
1.Java的内存模型(简称JMM):假如多个CPU运行多个线程(有线程在同时运行)->每个线程运行在不同的CPU上面->假如要读取变量,那应该是先从主内存中开始读取->然后加载到各自的工作内存中,然后再做其它的一些运算,如果我们的某一个变量在工作内存中被改变了,那就很有可能出现bug。(好处:运行速度快;坏处:可能出现bug)
2.volatile作用:保存共享变量在多个线程多个副本的可见性
在这里插入图片描述

5.JVM笔记

数据结构外网https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
深入了解Java内存模型JMM与volatile关键字
深入汇编语言底层理解volatile关键字
在这里插入图片描述
在这里插入图片描述

2月9日
1.~java虚拟机内存结构:虚拟机包括软件和硬件两种:像我们通常下载安装的Linxs、Oracle属于硬件虚拟机;容器技术如Docker属于软件虚拟机
2.怎么可以拿到class文件:通过IO流、通过jar(加载磁盘上的一些文件)、从网络上读取、从数据库区拿一段
3.类加载机制:①类加载器–找到我们的类(首先要找到class)
②类加载器只分为两种:启动类加载器和其它类加载器(扩展类加载器、系统类加载器、用户自定义加载器)
③加载类只能由JVM进行
④确定一个类的唯一性(确定一个class的唯一性):权限命名和加载类类加载器的实例
⑤启动类加载器在JVM里面是由c或c++语言来实现的
⑥把一个类加载进内存当中来,完了之后——>一个由一个静态存储结构转换到了内存当中一个动态的数据,要用到这些数据,不同的数据要放到不同的内存当中去
4.本地方法栈:启动线程(由JVM来启动的)
5.JVM由三个主要的子系统构成:⑴类加载气系统;⑵运行时数据区(内存结构);⑶执行引擎
6.类是由执行引擎执行的

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值