java虚拟机jvm启动后java代码层面发生了什么?

java虚拟机jvm启动后java代码层面发生了什么?

0000 我想验证的事情

java代码在被编译后可以被jdk提供的java命令进行加载和运行, 在我们的程序被运行起来的时候,都发生了什么事情, 下面就来探究下这个问题, 这个问题被拆成了两个问题, 第一个问题用来确定发生了哪些事情, 第二个问题用来确定这些事情是如何进行的.

  1. java进程里面都发生了哪些活动?
  2. 这些活动在java代码(反编译或者是源码)级别有所体现吗?

0001 寻找验证的方式

当我在探究上面两个问题时, 我想了很多方式去探究这两个问题,下面是我想到的方法

  1. java官方文档? 没有找到
  2. 搜索引擎? 没有找到
  3. idea中debug? 有点线索

在idea中打上断点然后debug时, 我发现了一个东西,以下是idea中的debug截图

idea调试面板

看到了这个关于线程和调用堆栈的线索, 那么java代码层面中发生了哪些事情就好确定了
通过线程名字可以看出这个线程主要负责的事情.

线程名称

0002 确认验证的入口

idea中的debug窗口的线程选择下拉框显示了一些可以进行debug操作的线程, 那么可以断定这几个线程都有对应java代码入口, 我们可以根据这些堆栈的入口来进行代码阅读, 感兴趣的可以看看里面究竟发生了哪些事情
idea中的可debug的线程没有通过jstack命令显示的线程多, 下面是通过jstack命令dump出来的数据:

"RMI TCP Connection(2)-192.168.191.1" #18 daemon prio=5 os_prio=0 tid=0x000000001b409800 nid=0x80a4 runnable [0x000000001c93d000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
- locked <0x00000000d7520cb0> (a java.io.BufferedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:555)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$Lambda$3/1223273742.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

Locked ownable synchronizers:
- <0x00000000d6c99530> (a java.util.concurrent.ThreadPoolExecutor$Worker)

"JMX server connection timeout 17" #17 daemon prio=5 os_prio=0 tid=0x000000001ae9e000 nid=0x8088 in Object.wait() [0x000000001c63f000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d715f378> (a [I)
at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(ServerCommunicatorAdmin.java:168)
- locked <0x00000000d715f378> (a [I)
at java.lang.Thread.run(Thread.java:748)

Locked ownable synchronizers:
- None

"RMI Scheduler(0)" #16 daemon prio=5 os_prio=0 tid=0x000000001b1c6800 nid=0x8084 waiting on condition [0x000000001c53e000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000d69fbee0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

Locked ownable synchronizers:
- None

"RMI TCP Connection(1)-192.168.191.1" #15 daemon prio=5 os_prio=0 tid=0x000000001ae1a800 nid=0x8080 runnable [0x000000001c43d000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
- locked <0x00000000d6ddc2e0> (a java.io.BufferedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:83)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:555)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$3/1223273742.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

Locked ownable synchronizers:
- <0x00000000d6c93ac0> (a java.util.concurrent.ThreadPoolExecutor$Worker)

"RMI TCP Accept-0" #14 daemon prio=5 os_prio=0 tid=0x000000001a833800 nid=0x8074 runnable [0x000000001c23e000]
java.lang.Thread.State: RUNNABLE
at java.net.DualStackPlainSocketImpl.accept0(Native Method)
at java.net.DualStackPlainSocketImpl.socketAccept(DualStackPlainSocketImpl.java:131)
at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:409)
at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:199)
- locked <0x00000000d6be9bb0> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(ServerSocket.java:545)
at java.net.ServerSocket.accept(ServerSocket.java:513)
at sun.management.jmxremote.LocalRMIServerSocketFactory$1.accept(LocalRMIServerSocketFactory.java:52)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:405)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(TCPTransport.java:377)
at java.lang.Thread.run(Thread.java:748)

Locked ownable synchronizers:
- None

"Service Thread" #12 daemon prio=9 os_prio=0 tid=0x000000001a653800 nid=0x3be8 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"C1 CompilerThread2" #11 daemon prio=9 os_prio=2 tid=0x000000001a63f000 nid=0x70b8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"C2 CompilerThread1" #10 daemon prio=9 os_prio=2 tid=0x000000001a5ed800 nid=0x7898 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"C2 CompilerThread0" #9 daemon prio=9 os_prio=2 tid=0x000000001a5ec800 nid=0x79a4 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"JDWP Command Reader" #8 daemon prio=10 os_prio=0 tid=0x0000000018458800 nid=0x7520 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"JDWP Event Helper Thread" #7 daemon prio=10 os_prio=0 tid=0x0000000018455000 nid=0x7c44 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"JDWP Transport Listener: dt_socket" #6 daemon prio=10 os_prio=0 tid=0x0000000018449000 nid=0x7a50 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x00000000197b3000 nid=0x3250 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001842a800 nid=0x4c8c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE

Locked ownable synchronizers:
- None

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x00000000037bd800 nid=0x764c in Object.wait() [0x000000001976f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5d88ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x00000000d5d88ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)

Locked ownable synchronizers:
- None

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x00000000037bc000 nid=0x3c8c in Object.wait() [0x000000001966e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5d86bf8> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000000d5d86bf8> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

Locked ownable synchronizers:
- None

"main" #1 prio=5 os_prio=0 tid=0x00000000036c4000 nid=0x1cb0 runnable [0x00000000035bf000]
java.lang.Thread.State: RUNNABLE
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:255)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
- locked <0x00000000d5de89a8> (a java.io.BufferedInputStream)
at com.TaskTest.main(Test.java:179)

Locked ownable synchronizers:
- None

"VM Thread" os_prio=2 tid=0x00000000183d8000 nid=0x6d38 runnable

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000036e2800 nid=0x7e88 runnable

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000036e4000 nid=0x35e4 runnable

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00000000036e5800 nid=0x4ed4 runnable

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00000000036e7000 nid=0x702c runnable

"VM Periodic Task Thread" os_prio=2 tid=0x000000001a69f000 nid=0x2af8 waiting on condition

JNI global references: 5253

可以看出来jstack导出的线程有些有调用堆栈, 有些没有, 是这样的, 没有堆栈的线程应该是jvm的一些核心线程, 这些核心线程提供了jvm的核心功能, 比如垃圾回收, 即时编译等. 带有堆栈的这些线程都是由java代码作为入口构建出来的, 所以我们能根据这些入口去查看里面的具体逻辑, 这些线程中有一个线程main, 这个线程就是为带有main方法入口的java应用构建出来的, 这个线程主要执行动作就是java应用由入口方法所触发的程序逻辑.

另外带有堆栈信息的这些线程, 在执行其自身代码的逻辑之外, 还会被jvm用于执行类加载这个动作. 如何验证这个类加载的动作呢, 如果你用的idea, 在设置中开启debug时进入类加载器断点, idea默认不开启这个动作, 然后把断点打点到类加载器的loadClass这个方法中, 给出以下具体位置:sun.misc.Launcher.AppClassLoader#loadClass, 这只是咱们项目代码中的定义类型的类加载器.

那如何确定是某个类的类加载器呢, 大家可以在自己的先获取类的类对象, 根据类对象的方法getClassLoader就可以确认类加载器了, 对于AppClassLoader这个类加载器大家肯定不会陌生, 比较有名双亲委派模型就是由这个类作为入口实现的, 大家有兴趣的可以去扒下代码, 验证下自己读过的文章是不是和代码一致. 最后以debug模式启动你的main代码, 你就可以命中类加载器中的代码了. 好了, 好好琢磨琢磨这些代码逻辑吧.

下次再见

0003 网络资源

下面是一些本文的相关资源

JVM 内部运行线程介绍
https://www.cnblogs.com/williamjie/p/9389349.html
各个工具如何查找加载类
https://docs.oracle.com/javase/8/docs/technotes/tools/findingclasses.html
java虚拟机如何查找加载类
https://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html

原文地址:https://www.cnblogs.com/yuanlianxi/p/12349665.html

时间: 2024-08-24 11:31:37

java虚拟机jvm启动后java代码层面发生了什么?的相关文章

《深入理解Java虚拟机 JVM高级特性...》核心笔记

深入理解Java虚拟机 JVM高级特性与最佳实践(第二版) 核心笔记 JAVA 环境: JAVA虚拟机高级特性: 一:java内存区域与内存异常 一):运行数据区     1:程序计数器(Program Counter Register),也称"PC寄存器" A:用来指示需要执行哪条指令的.(在汇编语言中,CPU在得到指令之后,程序计数器便自动加1或者根据                    转移指针得到下一条指令的地址,如此循环,直至执行完所有的指令.) B:由于在JVM中,多线程

深入java虚拟机-jvm高级特性和实战

第一部分 走近java 第一章 java技术体系 官方所定义的java技术体系 java程序设计语言 各硬件平台上的java虚拟机 Class文件格式 java api类库 来自商业机构和开源社区的第三方java类库 我们可以把java程序设计语言.java虚拟机.java api类库这三部分统称为JDK,是用于支持java程序开发的 最小环境把java api类库总的javaSE api子集和java虚拟机统称为JRE,是支持java程序运行的标准环境. 第二部分 自动内存管理机制 第二章 内

java虚拟机--JVM

java虚拟机 是安装在计算机操作系统上的一个虚拟计算机. 专门用于处理java程序和底层操作系统的链接工作,将java程序翻译成底层的操作系统可以理解的语言. 有别于JDK.JDK是java的开发环境,是java开发人员需要的,里面除了JVM,还有一些其他的东西.JVM是小于JDK的. JVM的结构图如下图所示: 1. 类加载器:加载类文件到内存.[这里的类文件是class文件] 2. 运行数据区:1中加载的class文件,全部保存在运行数据区.java能够很好的运行,也是得益于运行数据区的管

Java虚拟机JVM学习04 类的初始化

Java虚拟机JVM学习04 类的初始化 类的初始化 在初始化阶段,Java虚拟机执行类的初始化语句,为类的静态变量赋予初始值. 在程序中,静态变量的初始化有两种途径: 1.在静态变量的声明处进行初始化: 2.在静态代码块中进行初始化. 没有经过显式初始化的静态变量将原有的值. 静态变量的声明语句,以及静态代码块都被看做类的初始化语句,Java虚拟机会按照初始化语句在类文件中的先后顺序来依次执行它们. 类的初始化步骤 1.假如这个类还没有被加载和连接,那就先进行加载和连接. 2.假如类存在直接的

深入Java虚拟机JVM类加载初始化学习笔记

1. Classloader的作用,概括来说就是将编译后的class装载.加载到机器内存中,为了以后的程序的执行提供前提条件. 2. 一段程序引发的思考: 风中叶老师在他的视频中给了我们一段程序,号称是世界上所有的Java程序员都会犯的错误. 一般不假思索的结论就是,a=1,b=1.给出的原因是:a.b都是静态变量,在构造函数调用的时候已经对a和b都加1了.答案就都是1.但是运行完后答案却是a=1,b=0. 为什么呢,这3句无非就是静态变量的声明.初始化,值的变化和声明的顺序还有关系吗?Java

Java虚拟机JVM学习05 类加载器的父委托机制

Java虚拟机JVM学习05 类加载器的父委托机制 类加载器 类加载器用来把类加载到Java虚拟机中. 类加载器的类型 有两种类型的类加载器: 1.JVM自带的加载器: 根类加载器(Bootstrap) 扩展类加载器(Extension) 系统类加载器(System) 2.用户自定义的类加载器: java.lang.ClassLoader的子类,用户可以定制类的加载方式. JVM自带的加载器 Java虚拟机自带了以下几种加载器. 1.根(Bootstrap)类加载器: 该加载器没有父加载器. 它

Java虚拟机JVM简单理解

Java虚拟机JVM的作用: Java源文件(.java)通过编译器编译成.class文件,.class文件通过JVM中的解释器解释成特定机器上的机器代码,从而实现Java语言的跨平台. JVM的体系结构包含三个主要的子系统和一个内存区,分别是: 垃圾回收器:用于回收堆(heap)中无引用的对象. 类装载子系统:定位及导入二进制class文件,校验被导入类的正确性,为类变量分配初始化内存,以及帮助解析符号引用. 执行引擎:执行被转载类中的方法指令. 运行时数据区:又叫做虚拟机内存或Java内存.

书籍推荐:《实战Java虚拟机——JVM故障诊断与性能优化》下载

本书详细介绍Java虚拟机的基本原理和优化诊断方法.其中重点介绍Java虚拟机的体系结构.常用的虚拟机参数.Java虚拟机的垃圾回收原理.算法以及目前虚拟机所支持的各种垃圾回收器及其区别.特点和使用方法.在实践和调优方面,重点介绍了Java的堆.栈分析方法,性能调优的一般思路.手段和工具.此外,还详细介绍了虚拟机内有关"锁"的实现以及优化方法. 作为对虚拟机的深入了解,本书还将详细介绍Java类的基本格式.装载过程和虚拟机的执行机制. Java虚拟机目前是Java.Scala.Cloj

深入java虚拟机(一)——java虚拟机底层结构详解

在以前的博客里面,我们介绍了在java领域中大部分的知识点,从最基础的java最基本语法到SSH框架.这里面应该包含了在java领域里面的大部分内容了吧.但是,那些知识点是让我们从一个应用的层面上了解了java,java程序真正底层的运行机制和一些底层虚拟机的工作我们还不了解,虽然这些内容在我们真正的开发中几乎用不到这些底层的东西,但对于我们对java的理解会有比较大的帮助.尤其也对以后java开发中的性能优化有很大帮助,可以使我们减少一些没必要的内存浪费等好处.所以,从今天开始,我将和大家一起