关于JVM的面试传送门:http://www.javashuo.com/article/p-fhbpjqer-ha.htmlhtml
JVM内存结构主要划分为:堆,jvm栈,本地方法栈,方法区,程序计数器java
以下图所示:面试
简单概述:每一个Java项目都有惟一对应的一个JVM实例,每个JVM实例又对应着一个堆区。Java堆是被当前应用全部进程所共享的,在JVM启动时就建立了。堆区的目的就是存放全部new建立实例对象和数组,因而可知堆对于当前应用来讲是全局的。数组
PS:这也就解释了假设有A,B两个Java项目,A项目有a,b,c三个类,a类能够调用b,c三个类,可是在B项目就不能够使用a,b,c三个类了数据结构
堆区的特色:堆的主要优点是灵活性,它能够的动态的分配内存。编译器不须要知道须要建立对象的时候须要分配多少内存给它,也不须要知道该对象的生命周期。new一个对象的时候会自动从堆中分配内存给它,而后若是长时间没有引用指向该对象时,JVM垃圾回收机制会在某个合适的时间点回收它。jvm
Java堆是jvm管理内存中最大的一块,它也是JVM垃圾回收的主要区域。虽然JVM垃圾回收机制会在某个合适的时间点自动回收没有引用指向的对象,可是做为java开发人员,掌握垃圾回收机制是很重要的,往后还要去学习这个....函数
虚拟机执行Native方法服务,执行不是用Java代码写的如C写的学习
当程序进入到一个方法时,会为这个方法分配一个私有存储空间,该空间为JVM栈。该线程为私有的。就比如你在a()方法中定义了int t = 1;可是在b方法中就不能直接用t。可是栈里面的数据是能够共享的。当方法结束时,该区域就释放了spa
栈的速度比堆要快,仅次于寄存器。可是缺乏灵活性,其数据大小和生存周期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段值就消失了).net
至于为何函数调用要采用栈调用,主要是契合数据结构中栈的先进后出原则,能够看下这篇链接:https://www.zhihu.com/question/34499262/answer/59415153
实例分析一:栈里面的数据是共享的
int a=1;
int b=1;
编译器预先处理int a =1;首先在栈中建立一个变量为a的引用,而后去栈中查找有没有字面值为1的地址,没有就开辟一个存放字面值为1的地址。接着执行b=1;建立一个变量为b的引用,因为已经存在字面值为1的地址了,因此b直接指向该地址。因此:出现了a,b同时指向1这个地址
特别注意:字面值的引用与对象的引用是不同的,假设两个类对象的引用指向同一个对象,若是一个引用对象修改了这个类的内部状态,那么另外一个引用对象也会便可反映出这个变化;而字面值引用则不会,假设在写上b=2,那么b引用会从新去JVM栈中去寻找字面值为2的地址,找不到则从新开辟一个地址来存储2,而后b引用在指向它
public class test2 { public static void main(String[] args) { int a = 1; int b = 1; // 1.建立变量为a的引用,在JVM栈中开辟字面值为1的地址,a在指向它 // 2.建立变量为b的引用,栈中已存在字面值为1的地址,b直接指向该地址。因此a,b地址相同 System.out.println(a == b); //true b = 2; System.out.println(a==b); //false } }
public class test { int num = 1; public static void main(String[] args) { // 建立变量为a的对象引用,new test()在堆中分配内存存储该对象,a再指向堆区中该对象的地址 test a = new test(); // 建立变量值为b的引用对象,指向a指向的堆区中地址 test b = a; System.out.println(a == b); b.num = 2; //这里就属于另外一个对象引用修改了该对象的内部状态,致使a受影响了 System.out.println(a.num); // 2 若是是test b = new test()则输出1,由于指向的不是同一个对象 // 这里又在堆区中给test对象分配了内存 test c = new test(); System.out.println(a == c); } }
关于包装类型数据:如Integer,Double,Float等将基本数据类型包装起来的类,它们存在于堆区中。Java用new()来显示的告诉编译器要建立。以后将对包装类型作一下整理,尤为是地址指向
http://www.blogjava.net/hgc-ghc/archive/2013/05/02/398675.html
方法区也同堆同样是被全部线程所共享的,它里面存放着satic修饰的代码和类信息,常量(final修饰)
线程私有,占用内存小。
字节码行号指示器,解释器经过它来选取下一条执行的字节码指令
不会有 OutOfMemoryError