Java语言写的源程序经过Java编译器,编译成与平台无关的‘字节码程序’(.class文件,也就是0,1二进制程序),而后在OS之上的Java解释器中解释执行,而JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。html
1、JVM原理java
1. JVM简介linux
JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。它是一种利用软件方法实现的抽象的计算机基于下层的操做系统和硬件平台,能够在上面执行java的字节码程序。缓存
java编译器只要面向JVM,生成JVM能理解的代码或字节码文件。Java源文件经编译成字节码程序,经过JVM将每一条指令翻译成不一样平台机器码,经过特定平台运行。数据结构
[/erji]2. Java语言运行的过程[/erji]
Java语言写的源程序经过Java编译器,编译成与平台无关的‘字节码程序’(.class文件,也就是0,1二进制程序),而后在OS之上的Java解释器中解释执行。jvm
JVM运行原理及Stack和Heap的实现过程模块化
3. JVM执行程序的过程操作系统
I. 加载class文件。线程
II. 管理并分配内存。翻译
III. 执行垃圾收集。
JRE(java运行时环境)由JVM构造的java程序的运行环境
JVM运行原理及Stack和Heap的实现过程
2、JVM中的Stack和Heap
在JVM中,内存分为两个部分,Stack(栈)和Heap(堆),这里,咱们从JVM的内存管理原理的角度来认识Stack和Heap,并经过这些原理认清Java中静态方法和静态属性的问题。
1. 简介
Stack(栈)是JVM的内存指令区。Stack管理很简单,push必定长度字节的数据或者指令,Stack指针压栈相应的字节位移;pop必定字节长度数据或者指令,Stack指针弹栈。Stack的速度很快,管理很简单,而且每次操做的数据或者指令字节长度是已知的。因此Java基本数据类型,Java指令代码,常量都保存在Stack中。
Heap(堆)是JVM的内存数据区。Heap的管理很复杂,每次分配不定长的内存空间,专门用来保存对象的实例。在Heap中分配必定的内存来保存对象实例,实际上也只是保存对象实例的属性值,属性的类型和对象自己的类型标记等,并不保存对象的方法(方法是指令,保存在Stack中),在Heap中分配必定的内存保存对象实例和对象的序列化比较相似。而对象实例在Heap中分配好之后,须要在Stack中保存一个4字节的Heap内存地址,用来定位该对象实例在Heap中的位置,便于找到该对象实例。
下图为JVM的体系结构:
JVM运行原理及Stack和Heap的实现过程
2. 什么是数据、什么是指令,对象的方法和对象的属性又是什么?
1)方法自己是指令的操做码部分,保存在Stack中;
2)方法内部变量做为指令的操做数部分,跟在指令的操做码以后,保存在Stack中(其实是简单类型保存在Stack中,对象类型在Stack中保存地址,在Heap 中保存值);上述的指令操做码和指令操做数构成了完整的Java指令。
3)对象实例包括其属性值做为数据,保存在数据区Heap中。
非静态的对象属性做为对象实例的一部分保存在Heap中,而对象实例必须经过Stack中保存的地址指针才能访问到。所以可否访问到对象实例以及它的非静态属性值彻底取决于可否得到对象实例在Stack中的地址指针。
3. 非静态方法和静态方法的区别?
非静态方法有一个和静态方法很重大的不一样:非静态方法有一个隐含的传入参数,该参数是JVM给它的,和咱们怎么写代码无关,这个隐含的参数就是对象实例在Stack中的地址指针。所以非静态方法(在Stack中的指令代码)老是能够找到本身的专用数据(在Heap 中的对象属性值)。固然非静态方法也必须得到该隐含参数,所以非静态方法在调用前,必须先new一个对象实例,得到Stack中的地址指针,不然JVM将没法将隐含参数传给非静态方法。
静态方法无此隐含参数,所以也不须要new对象,只要class文件被ClassLoader load进入JVM的Stack,该静态方法便可被调用。固然此时静态方法是存取不到Heap 中的对象属性的。
小结:当一个class文件被ClassLoader load进入JVM后,方法指令保存在Stack中,此时Heap区没有数据。而后程序技术器开始执行指令,若是是静态方法,直接依次执行指令代码,固然此时指令代码是不能访问Heap 数据区的;若是是非静态方法,因为隐含参数没有值,会报错。所以在非静态方法执行前,要先new对象,在Heap中分配数据,并把Stack中的地址指针交给非静态方法,这样程序技术器依次执行指令,而指令代码此时可以访问到Heap数据区了。
静态属性和动态属性:
前面提到对象实例以及动态属性都是保存在Heap 中的,而Heap 必须经过Stack中的地址指针才可以被指令(类的方法)访问到。
所以能够推断出:静态属性是保存在Stack中的,而不一样于动态属性保存在Heap 中。正由于都是在Stack中,而Stack中指令和数据都是定长的,所以很容易算出偏移量,也所以无论什么指令(类的方法),均可以访问到类的静态属性。也正由于静态属性被保存在Stack中,因此具备了全局属性。
在JVM中,静态属性保存在Stack指令内存区,动态属性保存在Heap数据内存区。
总结:
1)栈是运行时的单位,而堆是存储的单位。
2)栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;堆解决的是数据存储的问题,即数据怎么放、放在哪儿。
4. 为何要把堆和栈区分出来呢?
第一,从软件设计的角度看,栈表明了处理逻辑,而堆表明了数据。这样分开,使得处理逻辑更为清晰。分而治之的思想。这种隔离、模块化的思想在软件设计的方方面面都有体现。
第二,堆与栈的分离,使得堆中的内容能够被多个栈共享(也能够理解为多个线程访问同一个对象)。这种共享的收益是不少的。一方面这种共享提供了一种有效的数据交互方式(如:共享内存),另外一方面,堆中的共享常量和缓存能够被全部栈访问,节省了空间。
第三,栈由于运行时的须要,好比保存系统运行的上下文,须要进行地址段的划分。因为栈只能向上增加,所以就会限制住栈存储内容的能力。而堆不一样,堆中的对象是能够根据须要动态增加的,所以栈和堆的拆分,使得动态增加成为可能,相应栈中只需记录堆中的一个地址便可。
第四,面向对象就是堆和栈的完美结合。其实,面向对象方式的程序与之前结构化的程序在执行上没有任何区别。可是,面向对象的引入,使得对待问题的思考方式发生了改变,而更接近于天然方式的思考。当咱们把对象拆开,你会发现,对象的属性其实就是数据,存放在堆中;而对象的行为(方法),就是运行逻辑,放在栈中。咱们在编写对象的时候,其实即编写了数据结构,也编写的处理数据的逻辑。
程序要运行老是有一个起点的。同C语言同样,java中的Main就是那个起点。不管什么java程序,找到main就找到了程序执行的入口:)
5. 堆中存什么?栈中存什么?
1)堆中存的是对象。栈中存的是基本数据类型和堆中对象的引用。一个对象的大小是不可估计的,或者说是能够动态变化的,可是在栈中,一个对象只对应了一个4btye的引用。
2)为何不把基本类型放堆中呢?由于其占用的空间通常是1~8个字节——须要空间比较少,并且由于是基本类型,因此不会出现动态增加的状况——长度固定,所以栈中存储就够了,若是把他存在堆中是没有什么意义的(还会浪费空间,后面说明)。能够这么说,基本类型和对象的引用都是存放在栈中,并且都是几个字节的一个数,所以在程序运行时,他们的处理方式是统一的。可是基本类型、对象引用和对象自己就有所区别了,由于一个是栈中的数据一个是堆中的数据。最多见的一个问题就是,Java中参数传递时的问题。
3)Java中的参数传递时传值呢?仍是传引用?程序运行永远都是在栈中进行的,于是参数传递时,只存在传递基本类型和对象引用的问题。不会直接传对象自己。
Java在方法调用传递参数时,由于没有指针,因此它都是进行传值调用
PS:堆和栈中,栈是程序运行最根本的东西。程序运行能够没有堆,可是不能没有栈。而堆是为栈进行数据存储服务,说白了堆就是一块共享的内存。不过,正是由于堆和栈的分离的思想,才使得Java的垃圾回收成为可能。