字节码就是Java方法(可以这样理解) Java程序执行过程; (1)首先源代码文件(.java)经过编译器(例如Eclipse)变成字节码文件(.class) (2)然后由JVM中的类加载器加载Class文件中各个类的信息 (3)加载完成后交由JVM进行引擎执行 那么在整个执行过程当中,JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存。 运行时数据区(JVM内存)(Java内存)分为 1、程序计数器 2、Java虚拟机栈 3、本地方法栈 4、Java堆 5、方法区 6、运行时常量池 7、直接内存 下面挨个介绍这七个区域 一、程序计数器(每个线程都有自己的程序计数器这样当线程执行切换的时候就可以在上次执行的基础上继续执行,) 1、由于在JVM中,多线程是通过线程轮流切换来获得CPU执行时间的,因此,在任一具体时刻,一个CPU的内核只会执行一条线程中的指令,因此,为了能够使得每个线程都在线程切换后能够恢复在切换之前的程序执行位置,每个线程都需要有自己独立的程序计数器,并且不能互相被干扰,否则就会影响到程序的正常执行次序。 2、 (1)当线程在执行Java方法的时候,程序计数器记录的是正在执行的虚拟机字节码的指令地址 (2)当线程在执行Native(本地方法)的时候,这个计数器的值为空 3、由于程序计数器中存储的数据所占空间的大小不会随程序的执行而发生改变,因此,对于程序计数器是不会发生内存溢出现象(OutOfMemory)的。 总结三条: (1)线程私有的。利用于多线程中,用于找到上一次执行到的地方。 (2)java方法:指令地址 Native:空 (3)不会出现内存溢出
二、Java虚拟机栈 1、线程私有的 2、每个方法在被执行的时候都会创建一个栈帧,栈帧里存储着局部变量表。局部变量表存放着这个方法里用到的基本数据类型,对象的引用和returnAddress类型(指向了一条字节码指令的地址) (定义基本类型变量的名字和对象引用都在这里) 3、虚拟机栈中定义了两种异常,如果线程调用的栈深度大于虚拟机允许的最大深度,则抛出StatckOverFlowError(栈溢出);不过多数Java虚拟机都允许动态扩展虚拟机栈的大小(有少部分是固定长度的),所以线程可以一直申请栈,直到内存不足,此时,会抛出OutOfMemoryError(内存溢出)。
三、本地方法栈: Java虚拟机栈是为字节码(也就是Java方法)服务的,而本地方法栈是为本地(Native)方法服务的,同样也有两异常。
四、Java堆 1、所有线程共享的 2、存放对象实例(对象,基本类型变量,数据)和Java虚拟机栈正好对应 3、Java堆时垃圾回收机制管理的主要区域 4、如果在堆内没有内存完成实例分配,并且堆也无法再扩展,将会抛出OutOfMemoryError(内存溢出)。
五、方法区 1、所有线程共享的 2、用于存储已经被虚拟机加载的类信息,常量(final),静态变量等(可以看作是永久代,也可以看作时堆的一个逻辑部分) 3、当方法区无法满足内存分配的需求的时候,将会抛出OutOfMemoryError(内存溢出)。
六、运行时常量池 1、方法区的一部分 2、用于存放编译期生成的各种字面量和符号引用 (我觉得运行常量池这里只需要知道JVM常量池保证相同的字符串直接量只有一个,多次出现时会被编译器优化,只创建一个对象。) 3、当常量池无法再申请到内存时候会抛出异常。
七、直接内存