网站首页 > java教程 正文
前言:
作为一个java程序员,应该要知道一段代码是如何在jvm里运行的,所以今天这篇文章就讲解下java程序运行原理分析。
正文:
一、Java的class文件的内容
1.首先编写一个简单的代码
public class StringDemo { public static void main(String[] args) { String s=new String("hello world"); System.out.println(s); } }
2.运行程序编译成class文件,class文件的查看可以用Java class文件分析工具 -- Classpy
3.这种字节码文件我们肯定看不懂,所以我们可以通过指令Javap来转换成我们人类可以看懂的
4.打开StringDemo.txt文件,即下图的内容
public class com.dada.demo.controller.StringDemo minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #8.#24 // java/lang/Object."<init>":()V #2 = Class #25 // java/lang/String #3 = String #26 // hello world #4 = Methodref #2.#27 // java/lang/String."<init>":(Ljava/lang/String;)V #5 = Fieldref #28.#29 // java/lang/System.out:Ljava/io/PrintStream; #6 = Methodref #30.#31 // java/io/PrintStream.println:(Ljava/lang/String;)V #7 = Class #32 // com/dada/demo/controller/StringDemo #8 = Class #33 // java/lang/Object #9 = Utf8 <init> #10 = Utf8 ()V #11 = Utf8 Code #12 = Utf8 LineNumberTable #13 = Utf8 LocalVariableTable #14 = Utf8 this #15 = Utf8 Lcom/dada/demo/controller/StringDemo; #16 = Utf8 main #17 = Utf8 ([Ljava/lang/String;)V #18 = Utf8 args #19 = Utf8 [Ljava/lang/String; #20 = Utf8 s #21 = Utf8 Ljava/lang/String; #22 = Utf8 SourceFile #23 = Utf8 StringDemo.java #24 = NameAndType #9:#10 // "<init>":()V #25 = Utf8 java/lang/String #26 = Utf8 hello world #27 = NameAndType #9:#34 // "<init>":(Ljava/lang/String;)V #28 = Class #35 // java/lang/System #29 = NameAndType #36:#37 // out:Ljava/io/PrintStream; #30 = Class #38 // java/io/PrintStream #31 = NameAndType #39:#34 // println:(Ljava/lang/String;)V #32 = Utf8 com/dada/demo/controller/StringDemo #33 = Utf8 java/lang/Object #34 = Utf8 (Ljava/lang/String;)V #35 = Utf8 java/lang/System #36 = Utf8 out #37 = Utf8 Ljava/io/PrintStream; #38 = Utf8 java/io/PrintStream #39 = Utf8 println { public com.dada.demo.controller.StringDemo(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 3: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/dada/demo/controller/StringDemo; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=2, args_size=1 0: new #2 // class java/lang/String 3: dup 4: ldc #3 // String hello world 6: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V 9: astore_1 10: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 13: aload_1 14: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 17: return LineNumberTable: line 5: 0 line 6: 10 line 7: 17 LocalVariableTable: Start Length Slot Name Signature 0 18 0 args [Ljava/lang/String; 10 8 1 s Ljava/lang/String; } SourceFile: "StringDemo.java"
5.上面的内容我们可以根据jvm指令码表,就知道什么意思啦
二、Java运行时数据区
1.方法区
Jvm用来存储加载类的信息、常量、静态变量、编译后的代码等数据
2.堆内存
Jvm启动时创建,存放对象的实例。垃圾回收器主要就是管理堆内存。
3.虚拟机栈
虚拟机栈,每个线程都在这个空间有一个私有的空间。线程栈由多个栈帧组成,一个线程执行一个或多个方法,一个方法对应一个栈帧。栈帧的内容包含:局部变量表、操作数栈、动态链接、方法返回地址、附加信息等。栈内存默认最大1M,超出则抛出StackOverflowError。
4.本地方法栈
和虚拟机栈功能类似,虚拟机栈是为虚拟机执行JAVA方法而准备的,本地方法栈是为虚拟机使用Native本地方法而准备的。
5.程序计数器
程序计数器记录当前线程执行字节码的位置,存储的是字节码指令地址,如果执行Native方法,则计数器值为空。每个线程在这个空间有一个私有的空间,占用内存空间很少。CPU同一时间,只会执行一条线程中的指令。JVM多线程会轮流切换并分配CPU执行时间的方式。为了线程切换后,需要通过程序计数器,来恢复正确的执行位置。
在了解上面的基础知识后,我们开始了解具体的执行过程。
三、Java虚拟机如何运行Java字节码?
标准JDK中的HotSpot是如何运行Java字节码的呢?(常见的虚拟机分三种1.HotSpot 2. JRockit 3.IBM的jvma)
需要从两个角度考虑:
虚拟机角度
底层硬件角度
1.1虚拟机角度
1.1.1从虚拟机角度是如何运行Java字节码的?
①首先会将Java代码编译成的class文件加载到JVM
②加载后的Java类会存放到方法区中。
③实际运行时,JVM会执行方法区内的代码。
④运行时,每当调用进入一个Java方法,JVM会在当前线程的Java方法栈中生成一个栈帧。
⑤退出执行的Java方法时,无论是不是正常返回,JVM都会弹出并舍弃掉当前线程的当前栈帧。
1.1.2栈帧是什么?
①用于存放局部变量、字节码的操作数
②栈帧的大小是提前计算好的。
③JVM不要求栈帧在内存空间内连续分布。
1.1.3JVM中内存组成部分有哪些?线程共享的是哪些部分?线程私有的是哪些部分?
线程共享:
①方法区:存放加载后的Java类
②堆:创建的对象实例
线程私有:
①Java方法栈: 面向Java方法
②本地方法栈: 面向C++写的native方法
③PC寄存器: 存放各个线程执行位置。
2.1硬件角度
2.1.1从硬件角度角度是如何运行Java字节码的?
①Java字节码无法直接执行
②JVM需要将字节码翻译成机器码
2.1.2JVM(如HotSpot)如何将字节码翻译成机器码?
两种方法:
①解释执行-逐条将字节码翻译成机器码执行
②即时编译(Just-In-Time compilation, JIT)-将一个方法中的字节码都编译成机器码后再执行。
总结:
Hello.java-->被编译成Hello.class,然后被加载到jvm的虚拟机里,存放到方法区内。实际运行代码时执行方法区的代码,每当调用进入一个Java方法,JVM会在当前线程的Java方法栈中生成一个栈帧,在栈帧内操作数栈根据指令码的顺序操作本地变量表来实现代码的执行,退出执行的Java方法时,无论是不是正常返回,JVM都会弹出并舍弃掉当前线程的当前栈帧。
讲解的部分可能不是很明白,大家可以多查阅一些资料,反复按照这个执行过程理解,我相信你很快就会形成自己的理解的。
以上就是我的对此问题的整理和思考。如果你对此话题有自己的思考和理解,也欢迎私信一起探讨!
而且私信我:“资料”,可免费领取更多学习资料哦
猜你喜欢
- 2024-10-20 深入理解Java虚拟机笔记(深入理解java虚拟机笔记怎么写)
- 2024-10-20 多图看懂Java虚拟机,JVM相关面试常考点全在这里了
- 2024-10-20 Java 虚拟机 (JVM):深入探讨其架构和性能
- 2024-10-20 Java后端精选技术:Java虚拟机工作原理
- 2024-10-20 简单分享 java 虚拟机学习(java虚拟机怎么学)
- 2024-10-20 JVM 虚拟机图文详解!真香!秒懂!一点都不难!
- 2024-10-20 读完这份JVM高级笔记,彻底玩转Java虚拟机,面试再也不用“虚”
- 2024-10-20 什么是JVM(Java虚拟机)(什么是java虚拟机?什么是jre?)
- 2024-10-20 深入解析java虚拟机:详细类可用机制,类加载、链接、初始化
- 2024-10-20 技术进阶:Java虚拟机(JVM)运行时详解
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)