文章目录

  • Pre
  • 运行时数据区总览
  • 线程栈
    • 概要
    • 栈内部主要组成部分
      • 局部变量
      • 操作数栈
      • 动态链接
      • 方法出口
      • 小结
  • 程序计数器
  • 本地方法栈
    • 测试demo
    • javap
    • JVM字节码指令集手册

Pre

JVM-01Java内存区域与内存溢出异常(上)【运行时区域数据】

JVM-02内存区域与内存溢出异常(中)【hotspot虚拟机对象】

JVM-03内存区域与内存溢出异常(下)【OutOfMemoryError案例】


运行时数据区总览

字节码文件被装载子系统装载到JVM中,字节码执行引擎负责执行这些字节码文件。
装载子系统和执行引擎都是C++的实现。

装载子系统: JVM-白话聊一聊JVM类加载和双亲委派机制源码解析

我们重点关注下运行时数据区域 ,先关注线程私有的这3个部分。


线程栈

概要

没给方法被执行的时候,JVM都会同步创建一个栈帧。

这个栈和数据结构的栈结构是一样的, FILO .

举个例子 ,方法A 中调用了方法B , 代码先执行方法A ,此时方法A 入栈, 然后调用方法B,这个时候方法B入栈 。 当方法B执行结束后,方法B出栈,回到方法A执行的地方,方法A继续执行,执行结束 ,方法A出栈。


栈内部主要组成部分

【Java代码】

   public int doSomething() {int a = 1 ;int b = 2 ;int c = (a + b) * 10 ;return c;}

【javap -c 反汇编】

如何操作的,见文末 ,JVM字节码指令集也见文末

  public int doSomething();Code:0: iconst_11: istore_12: iconst_23: istore_24: iload_15: iload_26: iadd7: bipush        109: imul10: istore_311: iload_312: ireturn
}

0: iconst_1
1: istore_1 【i —> int类型】

iconst_1 是个什么鬼? 查查操作手册

istore_1

iconst_0 和 istore_0 是默认存放调用该方法的对象。

这里就涉及到两个组成部分 【局部变量】 + 【操作数栈】

局部变量

0x04  iconst_1  将 int 型 1 推送至栈顶
0x3c  istore_1  将栈顶 int 型数值存入第二个本地变量
0x05  iconst_2  将 int 型 2 推送至栈顶
0x3d  istore_2  将栈顶 int 型数值存入第三个本地变量

比对代码

  int a = 1 ;int b = 2 ;

iconst_1 , 将 int 1 压入操作数栈 , istore_1 将栈顶 int 型数值存入第二个本地变量 ,这个时候 会先将 1 出栈,然后存入局部变量表。

istore_1 、istore_2 存入本地变量,就是放到了局部变量表。


操作数栈

0x04  iconst_1  将 int 型 1 推送至栈顶
0x05  iconst_2  将 int 型 2 推送至栈顶

这两步的意思 就是将代码中的 a 和 b 对应的值 1 和 2 压入 操作数栈 。

这个操作数栈 本身也是栈结构, FILO . 入栈 出栈


继续

 int c = (a + b) * 10 ;return c;
 4: iload_1    将第二个 int 型本地变量推送至栈顶  ----> a的值 1 入栈 (操作数栈)5: iload_2    将第三个 int 型本地变量推送至栈顶  ----> b的值 2 入栈 (操作数栈)6: iadd       将栈顶两 int 型数值相加并将结果压入栈顶  ---->  计算 a+b =3,结果压入栈顶 (a ,b 出栈,计算结果,然后将a+b的结果压入操作数栈)7: bipush        10      将单字节的常量值(-128~127)推送至栈顶  -----> 10 入栈 操作数栈)9: imul       将栈顶两 int 型数值相乘并将结果压入栈顶  ----> 计算乘积 3 * 10 ,将30压入操作数栈10: istore_3  将栈顶 int 型数值存入第四个本地变量  ------>  给 c赋值 11: iload_3   将第四个 int 型本地变量推送至栈顶  ----> 压入操作数栈 12: ireturn   从当前方法返回 int  ----> 返回

上面的行号 7 到9 ? 没有9 。 我们这个常量10 也要占位置嘛 。

计算 结果肯定是CPU执行的嘛 ,只不过数据是存放在内存中的。

简言之,操作数栈,是程序运行期间需要临时存放数据的内存空间。


动态链接

符号引用 替换为 直接引用。

我们知道在类装载的过程中,有个过程是【解析】


JVM-白话聊一聊JVM类加载和双亲委派机制源码解析

举个例子

 public static void main(String[] args) {Artisan artisan = new Artisan();artisan.doSomething();}

简单说当应用执行到artisan.doSomething()方法( 非静态方法),需要找到这个方法在方法区的常量池中的具体的位置,这个过程就是动态链接

方法区#运行时常量池 ,是方法区的一部分。 Class文件中的常量池表用于存放编译期间生成的各种字面量和符号引用,这部分内容将在类加载后放到方法区的运行时常量池中。


方法出口

   public static void main(String[] args) {Artisan artisan = new Artisan();artisan.doSomething();}public int doSomething() {int a = 1 ;int b = 2 ;int c = (a + b) * 10 ;return c;}

doSomething方法执行完要回到main方法中,方法出口中记录的就是记录main方法中的位置,不记录的话 ,不知道回到main方法中的哪一行继续执行哇~


小结


程序计数器

简单理解,可以理解为 记录程序执行的位置。

线程私有。

Java多线程,当线程A没有抢到CPU的执行权,如果没记录程序执行的位置,等下次抢到CPU执行权的时候,这尼玛咋弄? 重新开始执行吗?

显然是不行的,所以需要程序计数器来给每个线程的执行到的行号做下标记。各个现场的程序计数器互不影响,独立存储。

我们来看看javap -c 处理的反汇编

简单理解,可以理解为上面的行号, 实际上存储的是这行代码对应在内存中的指针位置。

字节码 由谁来执行? 肯定是字节码执行引擎嘛 ,所以 字节码执行引擎肯定知道程序的执行位置,这样 字节码执行引擎和程序计数器就关联起来了。


本地方法栈

native 方法 底层C++的


测试demo

package com.gof.test;public class Artisan {public static void main(String[] args) {Artisan artisan = new Artisan();artisan.doSomething();}public int doSomething() { // public 类型int a = 1 ;int b = 2 ;int c = (a + b) * 10 ;return c;}
}

javap

用法: javap <options> <classes>
其中, 可能的选项包括:-help  --help  -?        输出此用法消息-version                 版本信息-v  -verbose             输出附加信息-l                       输出行号和本地变量表-public                  仅显示公共类和成员-protected               显示受保护的/公共类和成员-package                 显示程序包/受保护的/公共类和成员 (默认)-p  -private             显示所有类和成员-c                       对代码进行反汇编-s                       输出内部类型签名-sysinfo                 显示正在处理的类的系统信息 (路径, 大小, 日期, MD5 散列)-constants               显示最终常量-classpath <path>        指定查找用户类文件的位置-cp <path>               指定查找用户类文件的位置-bootclasspath <path>    覆盖引导类文件的位置

-c 对代码进行反汇编

 E:\Program Files\Java\jdk1.8.0_161\bin> ./javap -c D:\IdeaProjects\GOF23\target\classes\com\gof\test\Artisan.class > Artisan.txt

查看 Artisan.txt

Compiled from "Artisan.java"
public class com.gof.test.Artisan {public com.gof.test.Artisan();Code:0: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: new           #2                  // class com/gof/test/Artisan3: dup4: invokespecial #3                  // Method "<init>":()V7: astore_18: aload_19: invokevirtual #4                  // Method doSomething:()I12: pop13: returnpublic int doSomething();Code:0: iconst_11: istore_12: iconst_23: istore_24: iload_15: iload_26: iadd7: bipush        109: imul10: istore_311: iload_312: ireturn
}

JVM字节码指令集手册

下载地址戳这里–>提取码:9ru5

JVM - 结合代码示例彻底搞懂Java内存区域_线程栈 | 本地方法栈 | 程序计数器相关推荐

  1. JVM - 结合代码示例彻底搞懂Java内存区域_对象在堆-栈-方法区(元空间)之间的关系

    文章目录 Pre 示例demo 总体关系 代码示例论证 反汇编 Pre JVM - 结合代码示例彻底搞懂Java内存区域_线程栈 | 本地方法栈 | 程序计数器 中我们探讨了线程栈中的内部结构 ,大家 ...

  2. 【JVM进阶之路】二:Java内存区域

    1.运行时数据区 Java 虚拟机定义了若干种程序运行期间会使用到的运行时数据区,其中有一些会随着虚拟机启动而创建,随着虚拟机退出而销毁.另外一些则是与线程一一对应的,这些与线程对应的数据区域会随着线 ...

  3. JVM程序计数器,虚拟机栈,本地方法栈

    程序计数器 它记录了程序执行字节码的行号和指令,字节码解释器的工作就是改变程序计数器的值,切换下一条需要执行的指令(分支,循环,跳转,异常等).java虚拟机是多线程通过轮流切换CPU时间片的方式实现 ...

  4. 彻底搞懂Java内存泄露

    Java内存回收方式 Java判断对象是否可以回收使用的而是可达性分析算法. 在主流的商用程序语言中(Java和C#),都是使用可达性分析算法判断对象是否存活的.这个算法的基本思路就是通过一系列名为& ...

  5. python 单例模式内存泄露_彻底搞懂Java内存泄露

    之前一直在简书写作,第一次发布到SF上来,也是第一次使用SF,后面会尽量同步到SF,更多文章请关注: 简书 编程之乐 转载请注明出处:谢谢! Java内存回收方式 Java判断对象是否可以回收使用的而 ...

  6. JVM面试重点总结(一)——java内存区域与内存溢出异常

    1.java内存区域是如何划分的?运行时数据区包含哪几部分? 2.方法.new.类在jvm内存中的产生区域? 3.什么是程序计数器?特点,作用?什么是"线程私有"的内存? 4.介绍 ...

  7. JVM【带着问题去学习 02】数据结构栈+本地方法栈+虚拟机栈+JVM栈运行原理

    1.数据结构栈 栈是一种比较简单的数据结构,后进先出.栈本身是一个线性表,但是这个表中只有一端允许数据的进出.栈的常用操作包括入栈push和出栈pop,对应于数据的压入和弹出.由于栈后进先出的特性,常 ...

  8. 300 行代码带你搞懂 Java 多线程!

    线程 线程的概念,百度是这样解释的: 线程(英语:Thread)是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可 ...

  9. 简单示例立马搞懂Java日期格式中yyyy-MM-dd HH:mm:ss和YYYY-MM-dd hh:mm:ss的区别

    word is weak,show me your code 啥也不说,上代码 /*** 测试两种不同的格式化*/public static void dateFormateTest() {Strin ...

最新文章

  1. Download interrupted: URL not found.
  2. Docker 命令终极教程:8步走
  3. 博鳌直击 | 大数据开发的最大障碍是什么?
  4. C#基础系列——语法
  5. MacBook电池健康程度的检查
  6. sklearn 线性回归_机器学习初级算法(二)——线性回归
  7. spss modeler模型应用
  8. 计算机的设备驱动程序在哪里查看,什么是驱动程序?如何查看电脑的驱动程序?看下面的文章就明白了...
  9. redis cli命令详解
  10. 微信小程序发布后使用本地图片不显示问题
  11. 一起来看看华为云的裸金属服务器
  12. mysql sql宽字节注入_sql注入之(宽字节注入篇)
  13. 美团饿了么外卖返利cps项目可以给你带来什么?
  14. Charles工具使用
  15. linux的常用备份方法,Linux系统下常用的数据备份方法
  16. OBAGI欧邦琪完成SPAC三方合并;JBS收购BioTech进入蛋白培植市场 | 知消
  17. [FPGA]1 MRCC与SRCC学习
  18. 齐鲁师范学院计算机专业在那个校区,齐鲁师范学院有几个校区及校区地址
  19. 基于neo4j知识图谱的旅游景点问答辅助系统
  20. a problem occurred with this webpage so it was reloaded

热门文章

  1. ajax在Xss中的利用,XSS高级利用
  2. 142. Leetcode 93. 复原 IP 地址 (回溯算法-切割问题)
  3. 104. Leetcode 337. 打家劫舍 III (动态规划-打家劫舍)
  4. [Solved] UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xff in position 0: invalid start byte
  5. 对比学习系列论文CPC(二)—Representation Learning with Contrastive Predictive Coding
  6. Pycharm环境调整
  7. Tableau实战系列Tableau基础概念全解析 (二)-万字长文解析数据类型及数据集
  8. 深度学习核心技术精讲100篇(四十八)-TB级的日志监控系统很难?带你使用ELK轻松搭建日志监控系统
  9. 过拟合(原因、解决方案、原理)
  10. 从TCP协议的原理来谈谈rst复位攻击