JVM笔记

1,什么是JVM

1.1 定义:

Java Virtual Machine ,是java程序的运行环境(java二进制字节码的运行环境)

1.2 优势:
  • 一次开发,到处运行
  • 自动内存谷粒,垃圾回收功能
  • 数组下标越界检查(防止越界覆盖其他数据结构的内存)
  • 多态
1.3 JDK与JRE的关系

JVM笔记_第1张图片
经常使用JPS/JAVAC/JAVAP等命令都是属于JDK,不属于JRE,有些服务器上只安装了JRE,也能运行JAVA服务,但是不能通过JPS查看java进程,不能使用jmap等性能检测工具。

2,学习JVM有什么用?

2.1 提升面试竞争力

学成文武艺,货与帝王家,JVM就是竞争力。

2.2 理解底层实现原理

JVM是内功,有深厚的内存,才能练出高强的招式。

2.3 工作必备技能

如何写出高性能的代码,如何设计高性能的应用架构,如何排查生产中出现的问题。只有学习了JVM,理解原理和常用工具,才能实现以上目标。

3,常见的JVM

3.1,实现了JVM规范的应用程序就是JVM

JVM笔记_第2张图片

4,学习路线

4.1 Jvm组成部分
  • Java 类加载
  • Jvm内存结构:方法区、堆、虚拟机栈、PC计数器、本地方法栈
  • 执行引擎 :解释器、即时编译器、GC
  • 本地方法接口

JVM笔记_第3张图片

4.2 学习顺序
JVM内存结构
GC垃圾回收
字节码
类加载器
Jvm引擎-即时编译器

5,程序计数器

5.1 Java代码的运行流程
Created with Raphaël 2.3.0 开始 Java编译器将Java代码编译成字节码 Jvm引擎中的解释器将Jvm字节码解释出机器码 CPU执行机器码 结束

计数器的作用是在解释器读取字节码的过程中,记住当前字节码的地址,程序计数器总是指向下一条字节码指令的位置。

6,程序计数器-特点

6.1 线程私有

容易理解,线程是CPU调度的基本单位,每个线程独立的执行代码,线程会竞争CPU资源,竞争失败会被挂起,挂起之后恢复需要知道下一个指令的地址,所以必须私有。

6.2 唯一不存在内存溢出的区域

7,虚拟机栈

7.1 线程私有

每个线程都有一个虚拟机栈,虚拟机栈是线程私有的

7.2 作用

在代码执行的过程中,会形成一个方法调用链,这个链本质是栈,每个方法调用在虚拟机中都会有一个栈帧与之对应,调用结束栈帧会被弹出。

7.3 结构
  • 局部变量表
  • 操作数栈
  • 返回地址(调用当前方法的地址)

8,Idea演示栈帧

使用Idea Debug程序时,可以看到方法调用链,就是虚拟机栈的外在表现形式,每个虚拟机栈都会对应一个局部变量表,存放局部变量的值,为了配合代码的执行,还必须有一个操作数栈,操作数栈在Idea中未通过UI呈现。

9~11,问题辨析1

1,垃圾回收释放设计栈内存?

不需要,栈帧在使用结束后就会被释放,不会继续存在,所以无需垃圾回收

2,栈内存越大越好吗?
  • 通过-Xss125m 设置虚拟机栈的大小
  • 不是越大越好,虚拟机栈是线程私有的,每个线程都有虚拟机栈,总的虚拟机栈大小=线程数*虚拟机栈大小,设置的就是单个虚拟机栈大小,所以虚拟机栈设置的太大,受限于内存总大小,线程数就会受到限制,所以虚拟机栈并不是越大越好。
3,方法内局部变量是否线程安全?

JVM笔记_第4张图片

  • m1的变量sb是线程安全的,在方法内定义、方法内使用,生命周期在方法内部
  • m2的变量sb不是线程安全的,其生命周期大于方法的周期,其作用范围大于方法内部的作用范围,可能会被其他线程共享
  • m3的变量sb虽然是在方法内部创建的,但是其引用会传递给其他方法,可能被其他线程共享,所以不是线程安全的

12~13 栈内存溢出

  • 方法调用链太深,栈帧太多,比如递归调用、死循环调用,会导致栈内存溢出
    JVM笔记_第5张图片

  • 栈太大,一个栈帧把栈内存撑爆。

复现 使用 -Xss1k,把栈内存设置为1k,创建一个大于1k的局部变量,就会栈内存溢出

  • 第三方包导致栈内存溢出:比如Dept内引用Emp类对象,Emp对象又引用Dept对象,在Json序列化时就可能导致栈内存溢出

你可能感兴趣的:(jvm,笔记)