java程序运行分析

使用工具:Eclipse Stardard 4.32版本(window7环境)

今天我们通过一个及其简单的例子来分析一个java程序是如何在我们的及其上跑起来的。部分内容是参考其他人的,会在参考的地方注明。

我的测试代码部分如下:


public class Test {

public static void main(String[] args) {

new Test();

Int test =1;//只是为了测试方便,去掉IO部分的分析

}

}

就是这么简单的代码,如何在我们的机器上跑起来,确实是需要一件很折磨人的事情

首先我们了解一下,我们的Eclipse是如何启动的.

参考书籍:Java编程思想(第四版)      深入理解java虚拟机(周志明著)

在这里我就不重复罗嗦详细的原理,因为那不是我想要说的,我想分析的是最简单的java程序是如何跑起来

的,而非一个exe是如何跑起来的

第一个步骤:


我们都会去双击一个eclipse.exe程序,然后会出现启动页面.

这个过程是会去读取相同目录下的配置文件eclipse.ini,读取出eclipse所需要运行的一些参数,

比如我们安装的jdk/jre路径在哪,在jdk1.5版本之前,在eclipse.ini中我们会发现-vm参数,但是后

续版本却没有该参数了,原因是后续版本的java程序不一定运行在sun的hotspot虚拟机中,也可能

运行其他虚拟,因此在后续版本中取消了该参数,然后会读取到启动eclipse程序的jar包startup.jar

我们通过解压\plugins\org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar(不同版本后面的

参数会不一样)会发现启动的Main类,然后通过Main类的静态方法main(String args)就会调用一系

列与本机有关的参数,通过JNI接口来调用本地方法启动我们的Eclipse了如果你感兴趣,可以读取上

面的四个参考博客,讲述的非常详细.

第二个步骤:

我们会运行我们编写好的代码,虽然我们只是在Eclipse点击了一个运行按钮,但是Eclipse却是

调用了我们安装在本机的jdk/bin中的工具,去启动我们的JVM,然后加载我们的类调入内存

中执行,因此我们所需要分析的就是这个步骤,究竟我们写好java代码,是怎么运行起来的.而我

们能做的就是通过调试跟踪源码的走向,来分析,JVM究竟做了哪些封装好的事情.

第三个步骤:

好了,我们开始吧.

我们在new Test()处设置好断点,然后右键以debug模式运行,会出来下面图片

我们可以在左上角看到,我们在我们的Test程序运行于本机上的56056号端口中,同时就我们的主线程运行在main方法中,这也佐证了,我们编写的main函数就是整个程序的主线程,而同时是Eclipse调用了我们安装在"C:\Program Files\Java\jre7\bin\javaw.exe"

下的JVM,如果我们此时在上面的路径中,如下图标注的地方:

会发现我们的一些JVM参数信息,如下图:

其中Command Line中就是我们启动的JVM部分参数,如果需要详细参数的话,可以利用jdk/bin中的jConsole.exe来调出JVM系统分析工具,运行如下图:

从途中我们可以看出,我们一个启动了三个进程,其中一个是Jconsole.exe本身,第二个是我们的Eclipse自身,第三个则是我们自己编写的Test类,我们在这里连接选择Test,进入之后我们就可以发现一个分析控制台了,我们点击进入VM概要,可以发现更多的JVM参数,如图:

从上图中我们可以看出,其实我们在Eclipse中属性中打开的的Command Line中参数只是上图最下侧部分的一部分数据而已.我们暂时不关注这些东西,我们只是去分析我们的程序是怎么运行起来的.

继续回到Eclipse中,我们通过单步调入的方式逐行去调试我们的程序,看我们的程序究竟是如何进入内存的。

从上面图中看到,在Test()中调用了init()方法,但是我们明明没有写该方法啊,我们注意一下的话就发现,init被<>包起来的,其实这是JVM去调用的,整个方法的作用就是在一个类进行对象实例化时调用的,Java编译器会为它的每一个类都至少生成一个实例初始化方法。在Class文件中,被称为"<init>",详情请参考深入理解java虚拟机一书,经过上述测试发现,当我们绕过IO部分得话,程序会很快退出该线程,因此为了更加详细一些,我还是增加了IO部分,因此代码部分就变更为:


Demo.java


package com.test;

public class Demo {

public void say(){

sayHello();

}

private void sayHello() {

System.out.println("hello");

}

}

Test.java


package com.test;

public class Test {

public static void main(String[] args) {

Demo demo = new Demo();

demo.say();

}

}

这样以来,我们就可以稍微复杂但分析这一情况。当进入debug模式后,我们会发现更我们刚才的情况不同了.

我们的Test类在初始化的时候,会出现一个ClassNotFoundException的异常提示,其实这是JVM在加载我们的类的时候一个验证阶段,为了安全,JVM做了大量的验证来保证我们编写的类文件必须是合法的.而是否存在该类便属于其中一个因素,当JVM发现我们编写的类却是存在的时候,就会去实例话它,但是在这之前,JVM还是需要做一些准备,初始化它的父类或接口,这是保证该类数据完整性的验证,因为在依赖倒置原则中,我们推荐每个类尽量有自己的类或者接口,而JVM也是认同这一点,但是不过我们所编写的类是否显示的继承于某一个类,都会默认去继承Object类的,因此,JVM接下来自然而然会去初始化我们的Object类,当JVM经过一系列的class文件的验证之后,才会通过不同的类加载器来加载我们的编写的类文件

我们可以看到不同的加载器最后才到达我们的Eclipse中的类加载器,最后才真正到了能够加载我们编写的类的加载器了ClassLoader

至此,程序将我们的Test文件通过编译解析到了内存中,

然后程序会继续随着程序的执行去实例化Demo类,至此,整个分析就结束了,鉴于第一次尝试分析,因此结果比较草率,后续我会整理一下,把整个思路顺一下,写一个完整点稍微复杂点的分析,整理成pdf以便下载。

java程序运行分析

时间: 2024-10-16 11:55:16

java程序运行分析的相关文章

Java开源运行分析工具(转)

FProfiler FProfiler是一个非常快的Java profiler.它利用BCEL和log4j来记录每个方法从开始到结尾的日记.FProfiler可以用来在你的应用程序,Servlet,Applet...中找出hotspots. 更多FProfiler信息 JRat JRat是一个Java Runtime分析工具包.它的目的是让开发者更好的明白Java程序动行时的状态.JRat包括但并不只局限于性能剖析. 更多JRat信息 EJP EJP(Extensible Java Profil

java程序运行原理

一.JRE.JDK.JVM 要了解java程序运行原理,首先需要了解知道jre.jdk.jvm这三者是什么,他们之间又有什么联系. JRE(JavaRuntimeEnvironment,Java运行环境),也就是Java平台.所有的Java 程序都要在JRE下才能运行. JDK(Java Development Kit,java开发工具包)是程序开发者用来来编译.调试java程序用的开发工具包.JDK的工具也是Java程序,也需要JRE才能运行.为了保持JDK的独立性和完整性,在JDK的安装过程

Java程序运行机制及运行过程

Java运行机制 Java虚拟机(Java Virtual Machine):Java虚拟机可以理解成一个以字节码为机器指令的CPU:对于不同的运行平台,有不同的虚拟机:Java虚拟机机制屏蔽了底层运行平台的差别,真正实现了“一次编译,随处运行”. Java垃圾回收(Garbage Collection):不用使用的内存空间应该回收:在C/C++等语言中,由程序员负责回收无用的内存:Java语言消除了程序员回收无用内存的职 责,它提供一种系统级线程跟踪存贮空间的分配情况,并在JVM空闲的时候,检

Java程序运行时的几个区域

Java运行时涉及到的区域 几个基本概念: 1.Java对象     2.Java方法    3.一个编译好的类,以class文件的形式出现 4.Java的本地方法   5.线程私有和线程共有 一.方法区(永久代) 和 堆(heap) 这两个区域是线程共有的,供所有线程使用.所以,对存放在这两个地方的资源进行操作时,如果是程序是多线程的,那么要考虑同步. 方法区存放的是类的类型信息.类的类型信息有,类的静态变量,其它从class文件中读取到的信息. 当用户访问一个类的静态方法或者类的静态变量,或

Java程序内存分析:使用mat工具分析内存占用

在工作中可能会遇到内存溢出这种灾难性的问题,那么程序肯定是存在问题,找出问题至关重要,上一篇文章讲了jmap命令的使用方法,当然用jmap导出的文件我们也看不懂啊,那就交给memory analyzer(mat)这个工具,让他帮助我们来观察程序的内存分布情况吧. 1. 用jmap生成堆信息 2. 将堆信息导入到mat中分析 3. 生成分析报告 Histogram Dominator Tree Top consumers Leak Suspects MAT 不是一个万能工具,它并不能处理所有类型的

从命令行及java程序运行MyBatis Generator 1.3.x生成MyBatis3.x代码

近期因为项目需要,调研了myBatis 3.x的使用,当然,顺便也就研究了一下使用Generator来通过逆向工程生成pojo,mapper等文件.使用这个工具之前,要先下载相关的jar包,我使用的是最新的mybatis-generator-core-1.3.2.jar.下面将generatorConfig.xml列出来: <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE generatorConf

Java 程序运行机制

目录 Java 程序运行机制 运行过程 注释 JDK, JRE, JVM 第一个 JAVA 程序 java命名规范 入门小游戏 Java 程序运行机制 运行过程 源文件 (a.java) Java 编译器 字节码文件(a.class) 进入 JRE ,分别执行 类装载器-->字节码校验器-->解释器 系统平台,执行. 注释 JRE 中包含 JVM (JAVA虚拟机); 其中的字节码校验器也是 JAVA 安全性的一种体现. 也正是因为有 JVM 的存在, 使得 JAVA 具有挂平台的特性; JV

Java程序运行原理分析

class文件内容 class文件包含Java程序执行的字节码 数据严格按照格式紧凑排列在class文件的二进制流,中间无分割符 文件开头有一个0xcafebabe(16进制)特殊的标志 JVM运行时数据区 线程独占: 每个线程都会有它独立的空间,随线程的生命周而创建和销毁 线程共享: 所有线程都能访问这块内存数据,随虚拟机或GC而创建和销毁 方法区 方法区是各个线程共享的内存区域 用于存储已被虚拟机加载的类信息, 常量,静态变量, 即时编译后的代码等数据 虽然Java虚拟机规范把方法区描述为堆

获取java程序运行时内存信息

由于最近想自己动手测试一下String和StringBuffer的效率问题,需要获取程序运行时的内存占中信息,于是上网查了一下,根据查到的资料写了个程序,发现结果有问题,才发现查到的资料是错误的.所以在这里跟大家分享一下获取内存占用的正确方法 错误的方法 //程序开始时:(先调用一下垃圾回收,但是不一定立即执行) Runtime.getRuntime().gc(); long initm=Runtime.getRuntime().freeMemory(); //程序结束时: Runtime.ge