2.1 程序计数器寄存器(The pc Register)
2.2 栈
JVM为每个新创建的线程都分配一个栈.也就是说,对于一个Java程序来说,它的运行就是通过对栈的操作来完成的。它用来保存局部变量的值,包括:1.用来保存基本数据类型的值;2.保存类的实例,即堆区对象的引用(指针)。3.用来保存加载方法时的帧,当嵌套方法调用时,嵌套越深,stack的内存就越晚才能释放,因此,在实际开发过程中,不推荐大家使用递归来进行方法的调用,递归很容易导致stack flow。
2.3 堆
每一个Java应用都唯一对应一个JVM实例,每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中。Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。
2.4 堆和栈的区别
2.5 方法区
JVM有一个被所有线程共享的方法区。方法区类似于传统语言的编译后代码的存储区,或者UNIX进程中的text段。它存储每个类结构例如常量池(constant pool),成员字段域和方法和构造函数,包含类和实例初始化和接口类型类型中用到的特殊方法的代码。
方法区在虚拟机启动时创建。尽管方法区在逻辑上是heap的一部分,简单的实现仍然可以选择对它既不回收也不压缩。
Byte Character Boolean Short Integer Long实现了常量池技术,Float,Double 没有实现常量池技术
· Integer i1 = 40;
· Integer i2 = 40;
因为Integer实现了常量池技术,所以在池中i1,i2指向同一个地址,故 i1 == i2 为true
· Double d1=1.0;
· Double d2=1.0;
因为Double 没有实现常量池技术,所以Doubled1=1.0;相当于Double d1=new Double(1.0);
d2类同,各自new了一个对象,所以d1和d2存放的指针不同,指向的对象不同,所以不相等
· Integer i4 = new Integer(40);
· Integer i5 = new Integer(40);
虽然Integer实现了常量池技术,但是他们各自new了一个对象。i4和i5 均是引用类型,在栈中存储指针,因为Integer是包装类。但是由于他们各自都是new出来的,因此不再从常量池寻找数据,而是从堆中各自new一个对象,然后各自保存指向对象的指针,所以i4和i5不相等,因为他们所存指针不同,所指向对象不同,故i4==i5为false。
但是需要注意的是:以上提到的几种基本类型包装类均实现了常量池技术,但他们维护的常量仅仅是【-128至127】这个范围内的常量,如果常量值超过这个范围,就会从堆中创建对象,不再从常量池中取。比如,把上边例子改成Integer i1 = 400; Integer i2 = 400;,很明显超过了127,无法从常量池获取常量,就要从堆中new新的Integer对象,这时i1和i2就不相等了。
对于i1==i2+i3、i4==i5+i6结果为True,是因为,Java的数学计算是在内存栈里操作的,Java会对i5、i6进行拆箱操作,其实比较的是基本类型(40=40+0),他们的值相同,因此结果为True。