代码执行流程
jvm内存结构,就需要我们结合图来分析,接下来我们会有一个内存结构图,和一份简单的Java源代码。来进行代码执行的分析,和jvm内存结构的分析。

首先在右上角,是一份Java源文件,对应Java Source,此时的java是源代码,并不能被jvm所解析执行,要经过javac 命令把源文件编译成 class文件,此时的class文件才能被jvm执行。此时我们通过java命令来执行class文件。在我们使用java命令执行class文件时,底层就会帮我们创建一个java虚拟机。对class文件进行执行。 在包括,类加载子系统之后的结构都是包括在虚拟机中的结构。
1.类加载
然后jvm会在虚拟机栈中创建一个main线程,由此可以看出,线程的创建是放入栈中。那么main线程 就要去执行main()方法,此时main()方法所对应的Main类,还并没有加载,这时就会通过类加载子系统 对class文件进行类的加载,这些类的基本信息,类中的静态变量,常量,jit即使编译器所编译的热点代码,都将会储存在方法区中,类的基本信息就包括,类的名字啊,有哪些成员,有哪些方法等。
注:在1.7之后的版本呢,静态变量并没有随着类信息存在方法区,也就是元空间。在类加载后,会随之在堆中生成class对象,而静态变量就存储在class对象的尾部。
这里可能还是有很多人可能不知道,方法区到底存储什么,我们就具体列出来。
- 类的基本信息
- 每个类的全限定名
- 每个类的直接超类的全限定名
- 该类是类还是接口
- 该类的访问修饰符
- 任何直接超接口的的全限定名的有序列表
- 字段信息
- 字段名称
- 字段类型
- 字段修饰符
- 方法信息
- 方法名
- 方法返回类型
- 方法修饰符
- 方法参数个数,参数类型等
- 运行时常量池
- 直接引用
- 符号引用转化为真实地址
- 字面量
- 字符串常量啊,final修饰的,数量值
- 直接引用
- 到类classloader的引用
- 到该类的类装载器的引用
- 到类class 的引用
- 虚拟机为每一个被装载的类型创建一个class实例,用来代表这个被装载的类。
2.执行main方法
类加载后,就可以执行main方法了,这时main线程中就压入了一个栈帧,一个栈帧就是一个方法。遇到Student类,发现方法区没有对应的类,重复第一个步骤,进行类加载,然后 stu 局部变量,将放在该栈帧中的局部变量表中。最后new Student类。在堆中创建一个Student实例。引用地址赋给stu。调用study方法,会再加一个栈帧,进行压栈操作。再调用hashCode()方法,由于hashcode方法是本地方法(native),所以这时后,需要引用本地方法栈中的方法进行调用。
3.垃圾回收
当把stu置成null时,此时student对象,并没有被引用,当发生垃圾回收时,会回收掉student对象。
4.解释器,和 JIT即时编译器
cpu并不能直接执行class文件,所以需要用解释器,将字节码文件,翻译成机器指令,才能让cpu进行读取。 解释器是一句一句进行翻译,十分耗性能。所以当有处代码,一直反复的进行执行,会变成热点代码。及时编译器,就会将该代码优化成机器码,下次再执行该代码时,就直接读机器码,就不用再进行解释。
5.程序计数器
这个差点忘了,因为虚拟机栈中,不会只有一个线程,当多个线程并发执行时,总会有线程没有分到时间片,此时,需要将执行到哪儿记录在程序技术器上,方便下次再分到时间片,cpu知道从何开始。
哪些区域会有内存溢出问题
内存溢出一般会报两种异常。
一个是:OutOfMemoryError
这个异常引起,主要有以下几个点。
- 当创建的对象达到一定数量时,切都不能被gc,那么堆内存就会溢出。从而导致异常。
- 当有许多的类加载到方法区中,方法区也会发生内存溢出。
- 当虚拟机栈中,创建了许多的线程。进而导致虚拟机栈内存溢出。
一个是:StackOverFlowError
这个异常就是当,在该线程中不断地反复的掉大量的方法,从而导致,栈内部内存溢出。
本文使用 文章同步助手 同步