JVM 中的 Java 基础类型
JVM 堆和栈
堆
JVM 堆是一个运行时数据区域,类的对象从堆中分配空间,这些对象通过 new 指令建立,通过垃圾回收销毁。
(注:静态变量存放在方法区中,JDK8 以后,将方法区迁移到了堆中)
堆的优势是可以动态的分配内存空间,编译器并不知道需要分配多少内存给堆,也不知道堆汇总的数据存活时间,因为堆内存是在运行时动态分配的,比较自由;
对于这个优势,JVM 也要响应的损失一部分性能与时间分配内存。
栈
栈中主要存放一些基本数据类型的变量(boolean,byte,short,int,long,floa,doublie,char)
栈的优势是存取速度比堆快,栈中数据可共享。
与堆不同,在栈创建的时候,编译器必须确切知道栈中的所有数据的确切大小和生命周期,因为要生成相应的代码,缺乏一定的灵活性。
Java 中的基础类型
类型 | 值域 | 默认值 | 虚拟机内部符号 |
---|---|---|---|
boolean | {false, true} | false | Z |
byte | [-128, 127] | 0 | B |
short | [-32768, 32767] | 0 | S |
char | [0, 65535] | ‘\u0000’ | C |
int | [-2^31, 2^31-1] | 0 | I |
long | [-2^63, 2^63-1] | 0L | J |
float | ~[-3.4E38, 3.4E38] | +0.0F | F |
double | ~[1.8E308, 1.8E308] | +0.0D | D |
类型存储
在 JVM 学习笔记一(Java 代码的执行) 中说道,调用一个方法时,JVM 会在 Java 方法栈中生成一个栈帧存放方法运行时数据,而且栈帧的大小是计算好的(上文中也有提及),在栈帧中存放着这个方法的 局部变量,字节码操作数栈,实例方法的 this 指针,形参
(栈帧 = 局部变量 + 字节码操作栈 + 实例方法 this 指针 + 形参)
在 JVM 规范中,局部变量相当于一个数组,并且可以用正整数来索引,除了 long 和 double 需要两个数组单元存储之外,其他基本类型或引用类型均占用一个数组单元,在栈空间上和 int 所占空间一样。(在 64 位的机器中占用 8 字节,32 位机器中占用 4字节)
以上情况仅仅出现于栈上,也就是说只会出现在方法区中;在堆中,这些类型该是几个字节还是几个字节,比如 boolean,还是只占用 1 字节。
类型加载
JVM 算数运算基本依赖于操作数栈,需要将堆中的 boolean,byte,char,short 加载到 操作数栈上,映射成 int 类型进行运算。如果是 byte 和 short 映射成 int,低位由 byte 和 short 值补充,高位若为正数补充 0,负数补充 1。
网络摘录:boolean 字段和 boolean 数组则比较特殊。在 HotSpot 中,boolean 字段占用一字节,而 boolean 数组则直接用 byte 数组来实现。为了保证堆中的 boolean 值是合法的,HotSpot 在存储时显式地进行掩码操作,也就是说,只取最后一位的值存入 boolean 字段或数组中。
(注:这里说的映射成 int 类型只是说加载到栈帧的时候,存储在堆里面的时候,以上 4 种类型仍然是 1字节,1字节, 1字节,2字节)