精华内容
下载资源
问答
  • 一个java程序是怎样运行起来的(3)

    万次阅读 2017-11-30 22:36:09
    一个java程序是怎样执行的

    接上一篇 一个java程序是怎样运行起来的(2),在jvm创建好后,就可以开始执行程序了。我们知道,程序执行的入口在main函数,所以我们首先得找到main函数,这得有个前提,main函数对应的类已经被jvm加载了,所以jvm做的第一件事就是去加载类。先来看下java类加载的机制,主要有以下几个阶段:

    1,加载:

    加载阶段可以参考java.lang.ClassLoader中loadClass方法,采用的是双亲委托进制进行加载,这个阶段首先找到对应的class文件,以二级制方式读入内存,按照jvm规范解析出所表达的数据结构,在内存中生成一个代表该类的java.lang.Class对象.

    2,验证:

    验证是确保当前class文件格式符合jvm规范,不会对jvm产生危害。验证工作并不是在加载之后才开始的,比如从class文件读入到内存后,解析其代表的数据结构时,我们首先会去校验魔数是否正确,以及版本号是否符合要求等

    3,准备

    准备阶段主要是为类的静态变量分配内存,设定初始值等工作

    4,解析

    常量池中的符号引用替换为直接引用,比如String str = "test",str指向常量池中"test"的地址

    5,初始化

    这个过程主要是执行类构造器的方法,静态类的赋值,静态代码块的执行。如果初始化一个类时,发现父类还没有初始化,则需要先初始化父类

    根据一个java程序是怎样运行起来的(1),类加载完成后,就可以找到main方法了,这时就可以开始执行main方法中的jvm指令了,下面以一个例子来解释其执行过程。

    测试代码如下:

    public class TestAdd{
    	public static void main(String[] args){
    		int a = 1;
    		int b = 2;
    		int c = a+b;
    		print(c);
    	}
    	
    	public static void print(int c){
    		System.out.println(c);
    	}
    }
    javac编译后,利用命令javap -c TestAdd,我们来看下在运行时究竟执行了哪些jvm指令

    public class TestAdd {
      public TestAdd();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
    
    
      public static void main(java.lang.String[]);
        Code:
           0: iconst_1
           1: istore_1
           2: iconst_2
           3: istore_2
           4: iload_1
           5: iload_2
           6: iadd
           7: istore_3
           8: iload_3
           9: invokestatic  #2                  // Method print:(I)V
          12: return
    
    
      public static void print(int);
        Code:
           0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
           3: iload_0
           4: invokevirtual #4                  // Method java/io/PrintStream.println:(I)V
           7: return
    }
    构造函数先不看,直接看main方法。函数的执行是在栈帧中执行的,执行的时候由程序计数器记录当前执行到哪个位置。栈帧存放在stack中,只有stack顶的栈帧当前有效,里面存放了本地变量表,操作数栈,返回地址等,本地变量表的大小,以及从操作数栈的深度在编译时就已经确定,运行时不会改变,如下图:


    他们之间的调用关系是栈帧1的函数调用了栈帧2中的函数,栈帧2中国的函数调用了栈帧3中的函数。有了这个基础,接下来看下上面的指令是如何执行的,入口在main方法,此时分配新的栈帧我把它标记为栈帧1,栈帧1处在stack顶,即为当前栈帧,执行main方法中jvm指令之前,栈帧1中的有关数据结构如下,本地变量表index为0变量存放的是函数的参数args:


    执行指令iconst_1,将int类型数字1push到操作数栈,此时栈帧1的数据结构为:


    执行指令istore_1,将栈帧1中操作数栈执行退栈操作,所得的值放入到本地变量表第1个变量中,此时栈帧1的数据结构:


    iconst_2,istore_2与上面同理,执行后栈帧:


    iload_1和iload_2分别把本地变量表中第一个和第二个变量的值压入到操作数栈,


    iadd指令,连续两次操作数栈执行退栈操作,将所得的值相加得到结果3再次压入操作数栈

    istore_3,将操作数栈栈顶元素退栈,所得的值存入第3个本地变量中


    iload_3,将本地变量表中第三个变量的值压入操作数栈中

    invokestaic 调用静态方法,此处存在方法调用,需要新开辟一个栈帧压入stack,并把变量值3入本地变量表,其返回地址为main方法中即将执行的指令return的地址,这个暂按照指令集的排列,标记为frame1_12吧,此时当前栈帧为栈帧2,运行时数据结构为:


    接下来看下print方法的执行,

    getstatic获取指定的field,

    iload_0,将变量0的值3压入操作数栈,此时数据结构为:


    invokevirtual执行打印方法,会新开辟一个栈帧栈帧3,将变量值3入栈帧3的本地变量表,其返回地址为frame2_7,执行return后,当前栈帧栈帧3退栈,栈帧2变成当前栈帧,发现当前执行的指令为return执行退栈操作,当前栈帧为栈帧1,此时栈帧1要执行的指令为return,退栈,至程序结束退出。

    至此,把java程序的执行过程简单过了一遍,过程非常粗糙,我目前对jvm的了解有限,后续有更好更深入的理解后,再回过头来丰富下。

    上面方法调用时的栈帧等数据结构可以参见本人编写的jvm尝试: https://github.com/reverence/czvm



    展开全文
  • 你有没有想过,你写的程序,是如何在计算机中运行的吗?比如我们搞Java的,肯定写过这段代码 public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } ...

    强烈声明:本文很干,请自备茶水!😎

    开门见山,咱不说废话!

    你有没有想过,你写的程序,是如何在计算机中运行的吗?比如我们搞Java的,肯定写过这段代码

    public class HelloWorld {
        public static void main(String[] args) {
            System.out.println("Hello World!"); 
        }
    }
    

    熟悉吧,可能大家都知道,运行输出“Hello World!”,不过嘞,今天我带你从内存和CPU的角度去剖析一下这段代码在计算机中是如何执行的。

    Hello World保存在哪?

    首先问你个很简单的问题,当你写下这段代码的时候,你把它保存在哪了,假如说你说是桌面,就像现在这样

    是的,一个HelloWorld.java文件就保存在了桌面上,这个叫做Java源文件,不过说是保存在桌面上这个有点模糊,这个桌面又是个啥呢,我们应该想象它保存在了我们电脑的哪个部分呢?一台计算机包含如下基本五个部分:

    1. 运算器
    2. 控制器
    3. 存储器
    4. 输入设备
    5. 输出设备

    在计算机中啊,保存信息主要靠存储器,而存储器又分为内部存储器和外部存储器,内部存储器就是内存了,而这个外部存储器主要就是磁盘了,磁盘又分为硬盘和软盘,而我们电脑中的大部分就都是硬盘了,这里也分为固态硬盘和传统机械硬盘。

    不管怎么说吧,磁盘也好内存也罢,就是用来存放数据的,那么我们就知道了我们写的这个Java源文件应该就是存放在电脑中的磁盘了。

    那么代码保存到硬盘中之后呢?

    今天的主角,CPU和内存

    代码被保存到硬盘之后,接下来就要CPU和内存登场了,提起精神了,超级干货来了。

    告诉你个秘密,理解CPU和内存是如何在一块工作的,是每个学编程必备的基础中的基础,反正就是很重要!

    我们在上面提到了硬盘,这里又说到了CPU和内存,那么我们就来看看这三个家伙

    硬盘,内存和CPU

    先看一张图

    这张图大致描述了三者的一个关系,什么关系嘞,数据读取的关系,我们之前不是说我们写的代码保存到了硬盘中了吗,如果要执行这段代码的话,需要把这段代码从硬盘中读取到内存中,此时的代码已经变成了二进制文件存储在内存中,为了更好的去理解,我们把上面的代码再进一步改写下:

    public class HelloWorld {
        public static void main(String[] args) {
            int a = 5;
            int b = 3;
            sum = a + b;
            System.out.println(sum); 
        }
    }
    

    也就是加入了一个基础的加法运算,此时这段代码已经变成二进制文件放到了内存中,现在要继续执行,也就是要执行代码的加法操作,此时的数据a和b,也就是5和3已经是二进制的形式在内存中,现在需要把a和b做加法运算,CPU收到这个指令(将a和b相加),就会去内存中将a和b读取,然后存放到自己的寄存器中,然后由CPU中的运算器去做加法运算,得到的结果依然放到寄存器中。

    是不是有点懵?啥是寄存器?运算器呢?别急,我们继续往下看。

    内存是个啥?

    这个内存是啥呢?内存条知道吧,我们电脑中的内存条,它是属于内部存储器,主要就是用来存放数据的,也可以理解为我们这里说的内存,这是实际存在的,我们可以看得见的内存条,但是关于数据存储,怎么存储,是不是还有点模糊,那么我们抽象点来说,这个内存其实就是一个个的小格子,就像这样:

    这些小格子就是用来存放数据和指令的,而且每个格子都有自己的编号,这个编号大家也熟悉,就是我们经常说的内存地址。

    另外你需要知道的是,计算机是只认识0和1的,所以存放在内存中的数据其实都是二进制文件了。

    CPU是个重点

    其实关于内存,先了解上面那些就足够了,内容比较多的就是CPU了,想必大家都听说过CPU就相当于人的大脑一样,对电脑来说,至关重要,所以啊,CPU的结构是真的复杂,怎么办?

    一般碰到这样的,我们就需要有选择的进行掌握和学习,因此对于CPU,你必须了解的两个东西,一是寄存器,另外一个就是运算器,为啥,这又是啥?

    想要搞明白这个问题,咱们需要先来看看如下这些知识点。

    CPU的特点

    首先,这家伙是真的复杂,除此之外嘞,你还需要知道对于CPU来说,必须要把数据读取到寄存器中才能做相应的运算,另外CPU的数据读写的速度是真的快,内存和硬盘根本没法比,可能你没啥概念,举个例子吧

    CPU这家伙执行一条指令大约需要耗时1ns,但是对于内存呢?它去硬盘读取数据至少8ms,在这段时间内,CPU可以执行大约800万条指令,说这个,主要是为了让你直观的感受到CPU是真的快。

    就像《码农翻身》一书中说的那样:

    CPU的运算速度快的丧心病狂,但是它能做的事情简单的令人发指

    啥?为啥做的事情简单的令人发指呢?

    别看CPU那么牛,那么复杂,那么快,它做的事情真的挺无聊的,总结起来,CPU主要就干如下四件事情:

    1、从内存中读取数据,然后放到寄存器中

    2、把寄存器中的数据写入到内存

    3、进行数学运算和逻辑运算(加减乘除,AND,OR)

    4、依据相应的条件进行跳转,执行其他指令(一条指令跳转到另外一条指令)

    不知道你发现没,我们似乎一直在提寄存器,这又是什么玩意?这就要看看CPU的构造了

    CPU的重点组成部分

    我们上面也说了,CPU的结构真的很复杂,但是我们需要重点关注如下几个重要组成部分:

    1. 寄存器
    2. 运算器

    没错就是这俩货,那他们是干啥的嘞,首先你得知道他们是CPU中的东西,这个寄存器啊,说白了就是存放数据的,是个存储部件,还记得之前说内存就是一个个的小格子吗?这个寄存器你就可以简单的想成也是小格子,放数据的。

    寄存器

    寄存器是存储部件,容量非常有限,能存储的数据的大小,现在来说一般有两种,也就是我们常听说的32位和64位,32位的寄存器就能存储4个字节的数据,64位的寄存器就能存储8个字节的数据,另外CPU也分为32位和64位其实就是由其中的寄存器的位数决定的,可想而知,即使是64位的寄存器也干不了啥大事啊,所以啊,现在的CPU一般都内置了很多的寄存器,依此来完成比较复杂的操作

    运算器

    另外一个就是运算器了,这个是计算的核心,主要的作用就是用来做加减乘除这些运算的,不过嘞,这里你需要知道的一点就是,运算器是没法直接操作内存中的数据的,很容易想到,运算器操作的数据是寄存器中存放的数据。

    CPU和内存的交互

    简单的了解了内存和CPU之后,我们就可以来看看程序代码是如何进一步被执行的,上面提到了,程序代码被读取到内存中了,现在要执行这段代码,那就需要CPU出马了,首先嘞,CPU会去读取需要进行操作的数据,对了,继续看这代码:

    public class HelloWorld {
        public static void main(String[] args) {
            int a = 5;
            int b = 3;
            sum = a + b;
            System.out.println(sum); 
        }
    }
    

    也就是需要读取数据a和b,那么读取到的数据a和b存放在哪了呢?根据我们上面对CPU简单的了解可知,数据a和b是被放到了CPU中的寄存器中了,看这个图

    在CPU中有两个比较重要的组件就是运算器和寄存器,寄存器有很多个,再看内存,是一个个的小格子,每个格子有编号,比如说现在数据a和b分别存放在#1和#2上,然后CPU将他们读取放在寄存器R1和R2上

    这个时候就要计算a和b的和了,然后就轮到运算器出马了,它会拿到寄存器R1和R2,也就是拿到数据a和b,然后做加法运算

    那么计算之后的结果也就是sum,运算器会再次把它放到寄存器,比如R1中,这个时候之前的数据b就会被覆盖,如此一来,CPU和内存就一起完成一次加法运算操作。

    这里其实我们把关注点聚焦到了加法运算操作,实际上,程序代码被装载近内存的时候会产生数据和指令两部分,数据我们都知道是啥,指令嘞?

    其实也好理解,指令就是说明程序该怎么执行,对于CPU来说就是告诉CPU该做什么,比如告诉CPU,读取数据a和b,然后再将他们相加,说白了,CPU是根据指令干活,指令让怎么干,咱就怎么干。

    因此,你必须告诉CPU该干啥,否则,CPU也很懵的呦。

    经过上面的简单介绍,我们再来看看CPU主要做的四件事情:

    1、从内存中读取数据,然后放到寄存器中

    2、把寄存器中的数据写入到内存

    3、进行数学运算和逻辑运算(加减乘除,AND,OR)

    4、依据相应的条件进行跳转,执行其他指令(一条指令跳转到另外一条指令)

    怎么样,是不是更加清晰明了!

    总结一哈

    这么一看,也没啥难的吗?总的来说啊,就是我们写的程序是放在硬盘中的,在运行的时候才会被调入到内存中,也就是说内存中的数据是从硬盘来的,而CPU中寄存器的数据又是从内存中装载进来的,然后CPU会根据相应的指令去操作寄存器中的数据,比如加减乘除什么的,以此来完成一个程序在计算机中的运行。

    一句话总结:

    本身程序是在硬盘上,需要把程序加载进内存,然后由CPU去执行

    另外对于内存啊,CPU什么呢还有很多有趣有用的知识,我们下次再讲!

    感谢阅读

    大学的时候选择了自学Java,工作了发现吃了计算机基础不好的亏,学历不行这是没办法的事,只能后天弥补,于是在编码之外开启了自己的逆袭之路,不断的学习Java核心知识,深入的研习计算机基础知识,所有心得全部书写成文,整理成有目录的PDF,持续原创,PDF在公众号持续更新,如果你也不甘平庸,那就与我一起在编码之外,不断成长吧!

    其实这里不仅有技术,更有那些技术之外的东西,比如,如何做一个精致的程序员,而不是“屌丝”,程序员本身就是高贵的一种存在啊,难道不是吗?

    非常欢迎你的加入,未来的日子,编码之外,有你有我,一起做一个人不傻,钱很多,活得久的快乐的程序员吧!

    回复关键字“PDF”,获取技术文章合集,已整理好,带有目录,欢迎一起交流技术!

    另外回复“庆哥”,看庆哥给你准备的惊喜大礼包,只给首次关注的你哦!

    任何问题,可以加庆哥微信:H653836923,另外,我有个交流群,我会***不定期在群里分享学习资源,不定时福利***,感兴趣的可以说下我邀请你!

    对了,如果你是个Java小白的话,也可以加我微信,我相信你在学习的过程中一定遇到不少问题,或许我可以帮助你,毕竟我也是过来人了!

    在这里插入图片描述

    感谢各位大大的阅读🥰

    展开全文
  • 如何运行一个nodejs 程序

    千次阅读 2019-09-04 20:11:27
    如何运行一个nodejs 程序 在Windows环境中运行NodeJS程序, 1.将代码文件保存到NodeJS安装文件的根目录,运行文件的时候, 2.需要打开cmd,然后输入NodeJS的安装盘名称, 例如:切换盘符到:D:,点击回车键; 再输入...

    如何运行一个nodejs 程序

    在Windows环境中运行NodeJS程序,
    1.将代码文件保存到NodeJS安装文件的根目录,运行文件的时候,
    2.需要打开cmd,然后输入NodeJS的安装盘名称,
    例如:切换盘符到:D:,点击回车键;
    再输入cd以及NodeJS的安装文件路径,点击回车键;
    然后输入node +保存的js文件名,然后点击回车键,
    即可将程序运行起来。
    在这里插入图片描述

    展开全文
  • 运行完第一个程序后,再选中第二个程序点击运行运行的还是第一个程序的结果,很奇怪,在spyder上不这样呀。网上也没有搜明白,就自己瞎倒腾了一下。 解决过程如下: 过程如下,我的理解是要切换控制台,我原来...

    献给和我一样的pycharm小白

    刚用pycharm,我感觉,pycharm比spyder好用一点,有树结构,有变量目录

    问题描述如下:

    我运行完第一个程序后,再选中第二个程序点击运行,运行的还是第一个程序的结果,很奇怪,在spyder上不这样呀。网上也没有搜明白,就自己瞎倒腾了一下。

    解决过程如下:

    过程如下,我的理解是要切换控制台,我原来运行的print1,现在切运行8.1.py

    展开全文
  • CPU时间的定义 CPU时间指标是CPU上花费的时间,不包括等待I/O或运行其他程序的时间。...但往往在一个程序运行过程中,CPU可能也会被其他程序占用,所以以下的测量方法,其实是一种近似测量CPU时...
  • 震惊:为什么在 Eclipse 中,运行程序结果却是另外一个程序
  • 如何运行一个Lingo程序

    千次阅读 2019-09-08 17:06:07
    点击工具栏那里有一个靶子样式的图标,或者直接ctrl+U,两种方法都可以运行程序。 图标长这样
  • 编写并运行一个java程序,HelloWord

    万次阅读 2018-04-04 22:48:46
    在编写第一个Java程序之前需要在电脑上配置好JDK,关于JDK的配置可以看这里: https://blog.csdn.net/du1393199551/article/details/79000969 编写并运行一个java程序,HelloWord: 【过程】编写----编译----...
  • 一个Java程序

    千次阅读 多人点赞 2019-12-06 19:24:15
    本文关键字:第一个Java程序、HelloWorld、编译、运行。Java语言具有跨平台性的特点,经过Java编译器编译后会产生相应的字节码文件,可以在任意一台安装了jvm(Java虚拟机)的设备上运行
  • package pxyhomeworkday10; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter;...实现一个记录程序运行次数
  • Windows:直接使用命令运行一个程序

    千次阅读 2019-04-09 10:53:56
    打开Windows运行命令 win+R,就是运行命令快捷键 ...3、conf:启动系统配置实用程序 4、charmap:启动字符映射表 5、calc:启动计算器 6、chkdsk.exe:Chkdsk磁盘检查 7、cmd.exe:CMD命令提示符 ...
  • eclipse总是运行一个程序

    千次阅读 2018-09-11 20:31:22
    这和java的特点有关,程序运行总是main()方法作为开始,那么既然现在的类不定义main(),就可以视作一个功能类,入口在原来的类,当然要从原来的程序开始运行啦。 改进方法就是寻找下刚写的类main()有没有误...
  • Qt程序运行一个实例

    千次阅读 多人点赞 2016-04-01 15:03:54
    #include QSharedMemory shared("name");//随便填名字就行 if (shared.attach()) {  return 0; } shared.create(1); 在main函数中加入以上代码,Qt生成的exe程序就只能启动次了。
  • 一个程序在计算机中到底是如何运行的?

    万次阅读 多人点赞 2016-09-22 23:46:09
    在《载入内存,让程序运行起来》一节中讲到,程序是保存在硬盘中的,要载入内存才能运行,CPU也被设计为只能从内存中读取数据和指令。 对于CPU来说,内存仅仅是一个存放指令和数据的地方,并不能在内存中完成计算...
  • 一、问题描述:  监控指定程序是否运行,如果程序没有... 、我们判断一个程序是否运行,可以通过查看该程序的进程信息来判断。  例: 判断程序 01FirstScript.sh 是否在运行  命令:ps -ef | grep 01FirstScri
  • 使用Dev C++编译运行一个C语言程序

    万次阅读 多人点赞 2017-11-16 19:12:08
    使用Dev C++编译运行一个C语言程序
  • 当我们写好一个C程序的时候,仅仅是一个.c的源程序,而我们运行完成之后就是一个.exe的可执行程序了,在这个过程中都发生了什么呢? (1).c的源程序会经过翻译环境和运行环境两个大的步骤。 其中,翻译环境包含...
  • //方法:只禁止多进程运行 using System; using System.Collections.Generic; using System.Windows.Forms; namespace DuoYeMianIE { static class Program { /// &lt;summary&gt; /// 应用程序的...
  • 在python中如果做到一段程序在同时运行两个代码块 例如:一个小游戏在运行另一段代码在 计时,时间一到游戏代码就会终止。这样的情况如何实现
  • c#中怎样判断一个程序是否正在运行? 我写了两个程序,其中程序2想判断程序1是否正在运行(这两个程序没有任何联系) 谢谢啊 if(System.Diagnostics.Process.GetProcessesByName("要获取的程序在进程中的称").To...
  • java 程序为什么总是运行一个程序

    千次阅读 2017-10-14 10:54:45
    个是文件错误 ...当建造一个新文件时应该有个好习惯,就是把文件名起好之后,顺便包下面的 public static void main(String[] args) 打上对号就可 解决办法复制现有文件粘贴到新建文件运行即可
  • ,但是在运行第二个程序的时候发现我的运行结果还是helloworld,这是为什么呢??? 后来发现是我的main函数拼写错了,其实造成这样结果的原因可能如下: 有可能main函数拼写错了,写成mian; 主函数是不是忘写...
  • 而我想要实现的是:在程序运行多个实例时激活的是第一个实例,使其获得焦点,并在前端显示.主要用到两个API 函数:ShowWindowAsync 该函数设置由不同线程产生的窗口的显示状态。SetForegroundWindow 该函数将创建指定...
  • 起因 最近想实现一个应用程序单例化的程序, 目前使QT运行一个实例有如下几种方式 1.QSharedMemory 使用共享内存,当第二个进程启动时,... 在程序运行的时候就在目录下创建一个文件,当程序运行时就判断这个
  • IntelliJ IDEA 运行你的第一个Java应用程序 idea运行main方法
  • 然而Runtime.getRuntime().exec(String s)检索进程树的方法 只能检测到exe进程 而我看了一下 java程序运行时 任务管理器中始终只有一个javaw.exe 这样就无法区别是那一个java程序在运行。不知还有别的办法能解决这...
  • 编写并运行一个Lisp程序

    万次阅读 2017-11-26 10:09:05
    我觉得接触一门新的编程语言的时候第一个程序的编写至关重要,这能够让我快速了解到简单的语法以及运行方法。而运行方法基本上是我更为关注的,因为这将是后期学习过程中不断打交道的东西。  为了能够弥补工作中...
  • 次开始接触这编译器的时候,我真不知道怎么运行Go程序 刚把环境搭配好了,写了Go程序运行一看,弹出窗口,最底下还有红字 Error:Working directory is not specified 这错误,真让人费解 然后我...
  • eclipse老运行一个程序之原因总结

    万次阅读 多人点赞 2017-10-20 13:53:06
    这和java的特点有关,程序运行总是main()方法作为开始,那么既然现在的类不定义main(),就可以视作一个功能类,入口在原来的类,当然要从原来的程序开始运行啦。 改进方法就是寻找下刚写的类main()有没有误...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,401,534
精华内容 2,160,613
关键字:

一个程序是如何运行的