作为JAVA的开发人员,需要知道JAVA是如何运行的,这个需要好好思考下。

(一)class文件内容

class文件包含JAVA程序执行的字节码,也就是说程序的执行是通过class里面的内容进行执行的。class文件内的信息严格按照一定的格式(虚拟机规范中的格式),紧凑排列在class文件中的二进制流,中间无任何分隔符。

① 分析class文件内的内容

文件开头有一个0xcafebabe 16进制的特殊的标志,cafebabe就是java的class的标识。

整个class文件很多很多的内容,用肉眼肯定是无法分辨的,

② class包含的内容

这个文件是有复杂格式,专门有JVM读里面的内容,方便阅读源码。

1.版本

源代码是由java的哪个版本的编译的。

2.访问标志

这个类是public 还是private 。

3.常量池

常量哪些。

4.当前类

当前类的名称,类的信息。

5.超级类

被继承的类,类信息。

6.接口

实现的接口是什么?

7.字段

8.方法

9.属性

(二)JVM运行时数据区

java 源代码编译后生成 class字节码,然后被加载到JVM运行时数据区里面

① 方法区

存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虚拟机规范中的一个逻辑区域(没有硬性的规定)。具体实现是根据不同的虚拟机来实现的。

如 oracle的Hotspot在java7中方法区放入永久代,java8放在元数据空间,并且通过GC机制对这个区域进行管理。

② 堆

对象,垃圾回收,都是在堆中。

堆内存还可以细分为:老年代,新生代(Eden,From Survivor,To Survivor)

JVM启动时就创建了,存放对象的实例,垃圾回收期主要就是管理堆内存,内存满了,就会出现OutOfMemroyEorror,后续在内存模型中,详细讲解。

③ 虚拟机栈

Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。一个方法对应一个栈帧。栈内存默认最大是1M,超出则抛出StackOverflowError。计算,保存一些信息都是在栈里面。

④ 本地方法栈

和java虚拟机栈类似,不同的是其为Native方法服务。它跟java虚拟机栈的区别就是执行的方法不同。

⑤ 程序计数器

当前线程所执行的字节码的行号指示器,每个线程都有一个独立的程序计数器。每个线程都在这个控件有一个私有的空间,占用内存空间很少。CPU同一时间,只会执行一个线程中的指令。JVM多线程会轮流切换并分配CPU执行时间的方式。为了线程切换后,需要通过程序计数器,来回复正确的执行位置。

学习java,学习jvm,了解JVM运行时数据区,这些就够了,下面【执行引擎】,【本地库接口】,【本地方法库】都是根据不同的操作系统,不同的平台,做了JVM的适配,例如:linux,windows的执行引擎,本地库接口都有一些的不同,JVM的目的就是一处编写导出的运行,作为开发人员掌握在执行引擎之上。

⑥ 线程独占

每个线程都会有它独立的空间,随着生命周期而创建和消亡。【虚拟机栈,本地方法栈,程序计数器。】。

⑦ 线程共享

所有线程能访问这块内存数据,随着虚拟机或者GC而创建和消亡。【方法区,堆】。

对象就是放入了堆中,也就是线程共享的。

(三)查看class文件内容

① 找个例子

public class Demo1{

public static void main(String[] args){

int x = 600;

int y = 100;

int a = x / y;

int b = 60;

System.out.println(a + b);

}

}

②执行下面的命令

使用Demo1.java进行测试,编译成class,完整的javap命令的解析结果

javac Demo1.java

// javap查看内容,说出Demo1.class所有的信息, 【>】意思是输入到一个Demo1.txt文件

javap -v Demo1.class > Demo1.txt

java -version

③ 版本号、访问控制

flags: ACC PUBLIC,ACC SUPER

④ 常量池

这个常量池指的类里面包含的静态常量,编译这个类需要用到的常量,类的名称类信息里面也是个常量,类本身需要用到的常量。

⑤ 构造方法

之前类并没有定义对应的构造方法,但是通过javap之后内部存在一个无参的构造方法。由此可见,没有定义构造函数时,会有隐式的无参构造函数。

⑥ 程序入口main方法

描述了方法的:访问控制,本地变量的数目,参数的数量,方法对应栈帧中操作的数栈的深度,JVM执行引擎去执行这些代码编译过后的指令码,javap翻译出来的操作符,class文件内存储的是指令码,前面的数字,是偏移量,jvm根据这个去区分不同的指令。工具叫【JVM指令码表】进行查阅查看具体指令的含义。

(三)程序完整运行分析

① 编译加载到方法区

编译加载到方法区,最后加载Demo1,其实一个JVM运行不止是一个Demo1,涉及到很多很多的类,会将所有的类信息存放到方法区里面,运行的一些常量会放在常量池里面,1.7和之前称为永久代,1.8开始称为元数据空间。

② 类加载进去,创建对象运行

类已经加载进去了,需要创建一个对象来进行运行,运行代码JVM创建线程来执行这些代码,一定是创建线程,需要配合【虚拟机栈】和【程序计数器】分配响应的空间,这里不涉及到本地代码因为咱们都是在JVM里面,Thread有一个独占的空间,其他区域有其他线程占领,【程序计数器】对应了字节码指令的地址。

③ main方法

线程独占空间,【程序计数器】标注当前这个线程执行到得位置记录下来有对应的序号,虚拟机栈里面开辟了一个空间,一个栈有多个栈帧组成,方法对应的一些操作,线程就是取一个或者多个,其实线程就是对应了一个或者多个栈帧,main方法的入口,也就是程序的入口,main方法栈帧包含本地变量表,操作数栈,Demo1 里面一共有5个变量,老铁可能问不是4个吗,哪里来了5个,因为main方法里面的String[] args也是一个啊。

解析方法,看不懂对照【JVM指令码表】

0: sipush 600 #将600这个数值压入到操作数栈,栈从下往上

3: istore_1 #将操作栈顶保存到本地变量表1,移除操作栈

4: bipush 100 #将 600这个数值保存后,将100放入操作数栈

6: istore_2 #操作数栈栈顶100 保存到本地变量表2上。

7: iload_1 # 读取本地变量1,压入操作数栈1

8: iload_2 # 读取本地变量2,压入操作数栈,它变成位置1了,前一个操作数栈位置变成2了

9: idiv # 将栈顶两int类型数相除,结果入栈600/100 = 6,原来操作数栈里面的100,600都移除。

10: istore_3 # 操作数栈栈顶6,保存到本地变量表3上。

11: bipush 60 #将 60这个数值保存后,将60放入操作数栈。

13: istore 4 # 将60放入操作数栈,放入本地变量表4的位置上。

15: getstatic #2 # 取货类或者接口字段的值并将其推入操作数栈,#2对应常量中,#2放入栈顶。

18: iload_3 #将本地变量3去取出压入操作数栈

19: iload 4 # 将本地变量4取出来压入操作数栈

21: iadd # 将栈顶两个int类型数相加,结果入栈。

22: invokevirtual #3 // Method java/io/PrintStream.println:(I)V

# 调用静态方法,新的一个方法,那个main方法不跑了,jvm会根据这个方法的描述,创建新栈帧,方法和操作从操作数栈中弹出来,压入虚拟机栈,然后虚拟机会开始执行虚拟机栈最上边的栈帧,执行完毕后,再继续执行main方法对应的栈帧。

25: return # void函数返回,main方法执行结果。

其实java的操作就是对于本地变量表,操作数栈,线程表里面的信息,操作,实现程序想要的效果,一定会要对照【JVM指令码表】来看一定点分析几个,java的套路你就了解了。

PS:本次将JVM运行的核心逻辑进行了详细的解析,JVM运行原理中更底层实现,针对不同的操作系统或者处理器,会有不同的实现,说了运行时数据区,讲到了栈,指令码的执行过程。这也是JAVA能够实现【一定编写,处处运行】的原因。下次说下Java线程。

java能够运行的原理_JAVA程序运行原理分析(一)相关推荐

  1. java线程运行无限次_java程序运行时到底有多少个活跃线程

    先贴上最原始的代码,疑惑的开始. public class Solution { public static void main(String[] args) { T t1 = new T(); T ...

  2. java生成cmd jar包_Java程序运行机制及cmd编译运行探究(二) cmd编译运行Java程序并打成jar包...

    目标:写一个RandomUtils.java工具类,返回一个随机数,并把这个类的字节码文件打成jar包 在Java运行机制及cmd编译运行探究(一)准备工作一文中,我总结了一部分要用到的cmd及编译运 ...

  3. 导入Java文件还是class文件_java程序运行的时候,是把所有的class文件都加载到内存吗?还是用的什么加载什么?...

    这一块还没有深入了解,不敢误人子弟. 我知道的,虚拟机在运行的时候,会预先加载一个常用的class,比如java.lang包下面的. 至于你在程序中自己引用的class文件/jar包之类的,是有一个加 ...

  4. java简述对象的组合_Java程序运行和对象创建过程简述

    Java中一个对象创建分为两个步骤: 加载类,创建对象. 加载类是将所写的程序.java文件编译生成的.class文件加载到内存中,保证了对象创建的预置环境.类加载完毕后才可以创建该类的对象. 第一步 ...

  5. java导出jar包后,程序运行时读取图片、音乐资源文件

    java导出jar包后,程序运行时读取图片.音乐资源文件 运行时程序就可以把图片.音乐资源加载进入了 start jre/bin/java -jar 名称.jar

  6. Simple Run Blocker:程序运行拦截器 阻止程序运行

    Simple Run Blocker可以直接拦截程序运行,阻止程序运行,是一个绿色免费软件,非常值得收藏,它用于临时限制某个软件发挥作用很好用,就看你的脑洞如何用了! 资源链接:Simple Run ...

  7. java运行原理_Java程序的加载与运行原理详解

    Java程序的运行包括两个非常重要的阶段: 一.编译阶段 第一步:程序员需要在计算机硬盘中任意位置创建一个.java扩展名的文件,该文件被称为 java源文件,源文件当中编写的是java源代码/源程序 ...

  8. java程序的运行环境简称_java程序的运行环境简称为什么?

    java程序的运行环境简称为JRE. Java运行环境(Java Runtime Environment,简称JRE)是一个软件,由太阳微系统所研发,JRE可以让计算机系统运行Java应用程序(Jav ...

  9. java运行慢_Java程序运行一段时间后越来越慢

    我有一个java程序,它是典型的机器学习算法,通过一些方程来更新某些参数的值: for (int iter=0; iter<1000; iter++) { // 1. Create many t ...

最新文章

  1. springcloud搭建篇
  2. 怎样判断RadioButtonList控件是否有选择
  3. web.xml初始化spring容器
  4. CF1019D-Large Triangle【计算几何,二分】
  5. prim求最短路径C语言,[图论]Prim算法求最小支撑树和最短路径
  6. 魔兽世界单机mysql密码_魔兽世界单机版-Trinity-Core数据库表解释
  7. iPhone如何快速设置自定义铃声?苹果手机铃声设置教程
  8. 电脑仙人掌机器人作文_仙人掌作文之电脑仙人掌机器人的童话作文
  9. 当 update 修改数据与原数据相同时会被更新吗?
  10. 如何提高文献检索能力?
  11. ntpd、ntpdate的区别
  12. AT指令集详解[zt]
  13. 爬取中国最好大学网数据(Python的Scrapy框架与Xpath联合运用)
  14. 深读源码-java同步系列简介
  15. 亚利桑那州接受加密货币纳税的计划受挫
  16. 微信公众平台群发规则说明
  17. 日常工作要想有效提高工作效率 常用的在线工具网站
  18. VS2015 kb2919355 解决方法汇总
  19. 软件工程 | 第五章 详细设计与实现
  20. 全屋2.5G,选购指南(本人亲测)

热门文章

  1. Java多线程开发系列之四:玩转多线程(线程的控制2)
  2. 802.11n兼容a/b/g问题(Legacy mode,Mixed mode,Greenfield mode)
  3. myeclipse中ALT+/怎么不管用了
  4. winx官方站点改版了!
  5. php 精度计算问题
  6. echarts常用实例
  7. Spring学习(22)--- AOP之Advice应用(下)
  8. 类和对象:一些相关的BIF - 零基础入门学习Python040
  9. 小论接口(interface)和抽象类(abstract class)的区别
  10. Javascript的变量作用域居然可以跨越多个函数!