前言
今天听一个师兄聊起他面试的经历,面试官问的第一个问题就是程序在main函数之前都进行写什么过程,他说他当 时答得不好,我自己想了想,虽然大致的能说上一些,但是感觉还是不太清晰,今天来总结一下。
C语言
由于机器只能认识二进制文件,所以用高级语言写成的程序必须得需要转换成为二进制磁盘文件,才能被机器执行 所以在main函数执行之前,就是一个文件的转换过程,如下:
- 预处理
去掉程序中的’#‘号开头的命令,如:
`#include<stdio.h>` 将库文件stdio.h直接插入源文件中
`#define PI 3.14` 将define定义的常量直接替换
`#if #else` 等条件编译处理
这时候得到的c程序一般以.i为扩展名
- 编译
即将.i文件转化成汇编语言程序,汇编语言程序与机器语言程序就比较接近了,这时候的程序以.s为扩展名
- 汇编
编辑器将汇编程序转化为二进制文件,即可重定位的目标程序(机器码),这个时候程序才被转化为二进制,之前 的两个阶段程序还是文本格式的。此时的程序文件以.o为扩展名
- 链接
将各个二进制文件整合为目标可执行程序,如printf函数,这是标准c库的函数,存在于一个名为printf.o的单独 编译好的目标文件中,链接器将其连接到目标文件中,生成可执行文件,它由源程序的名称来标识。这个时候的 程序是可以被加载到内存中执行的。
最后就是执行程序了,shell接收到用户的输入命令后,将用户的键入存放到寄存器中,一旦用户的键入结束,shell 将指定的代码和数据加载到内存,这么时候就开始执行main函数了。
java
由于c语言是过程性语言,所以在运行之前执行的有些繁琐,java作为一门解释型语言,它在运行之前的做的工作 显然没有c语言那么多。但是java也有一个编译的过程,也可将其称为半解释型语言,其过程为:
- 编译
编译会将.java源文件转换成为.class文件,这是一个字节码文件,如果用编译器打开会是一堆乱码,java程序的 执行速度不如c语言的原因部分是因为java程序和二进制程序中间需要转换成.class字节码文件。
.class文件主要分为两部分:
常量池 类名,成员变量名和方法引用
方法字节码 各个方法的字节码
可以通过.class文件的反编译来验证。不过在编译的时候,会先去找依赖的类,再编译当前类。
运行 java程序的运行过程有两个阶段:
- 加载 即类的.class字节码被加载到内存中,一般第一次使用的时候才会加载(惰性加载),这时候会为每个 类创建一个Class对象。
- 初始化 由可分为静态初始化和一般初始化,静态初始化在类加载时完成,一般静态初始化自会在Class对象首 次加载的时候进行一次,当创建一个对象时,首先会在堆上分配足够的存储空间,这时候这块存储空间会被清零, 即对象中的所有基本数据类型都会被设置成0,然后再执行字段定义处的初始化动作,最后执行构造器。
在java程序运行时最重要的是JVM,只有真正了解了JVM,才能对java程序的运行过程有个更深刻的了解。