对象大小
主要由3个部分组成,包括对象头、实例变量和内存填充。如图所示:
注意:
1. 对象头和虚拟机位数有关。在32位虚拟机下,对象头为8字节(包括4字节的Class指针和4字节的MarkWord。在64位虚拟机下,对象头为16字节(包括8字节的Class指针和8字节的MarkWord。如果64位开启指针压缩的情况下,存放Class指针的对象头为12字节(因为其中 的Class指针被压缩成4字节)。
2. 实例对象即类中所定义的各种类型的字段内容。例如:
3. 内存填充:用来保证(对象头+实例变量)的字节数必须是8的倍数。
基本数据类型长度
查看对象在堆上面开辟的大小:
思路:
mian函数设置为死循环,程序不结束就可以找到对应实体。生成log文件,便可查看占用空间大小。
步骤:
1.用记事本新建两个java文件,放在同一路径。
TestDemo.java
public class TestDemo{
public static void main(String[] args){
People p=new People();//注意P大写
while (true){
}
}
}
People.java
class People{
int a;
int b;
int c;
byte d;
}
2.在java文件所在目录的搜索框里输入cmd,打开两个DOS界面备用。
3.第一个cmd里:依次输入javac TestDemo.java
和java TestDemo
,对java文件进行编译和运行。
在第二个cmd里,依次输入jps
(用来查看TestDemo进程号)和jmap -histo:live 进程号>inform.log
(生成日志文件)
4.然后在java文件所在目录里查看刚才生成的inform文件。
5.搜索关键词People就能看到虚拟机为该类开辟的空间大小。
6.注意TestDemo.java是死循环,得到logn文件后在dos界面输入ctrl+c终止该程序。
大小分析:
由于指针压缩,对象头是12个字节;People类里有3个int和1个byte变量,共4*3+1=13个字节 。12+13=25不是8的倍数,系统给它内存填充7个,所以总大小为32。
其实内存中的Class文件是以字节流的形式存储的。所有16bit、32bit和64bit的数据分别都是通过读取2bytes、4bytes和8bytes的内存空间来构造存储的。多字节数据项总是以高位顺序存储,高字节优先。Java中最大的数据类型long和double都是占8bytes,所以以最大的8bytes为单位来进行内存分配。
内存对齐的好处
1.平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常
2.硬件原因:经过内存对齐之后,简化了处理器和内存接口的设计,可使CPU的内存访问速度大大提升。假设一个处理器要从内存中读取8bytes的数据A,则A地址必须是8的倍数,这样就可以用一个内存操作来读或者写这个A了。否则,我们可能需要执行两次内存访问,因为A可能被放在了两个8bytes的内存块中。
内存对齐其实就是空间换时间的思想。毕竟CPU比内存快了几个数量级。
参考资料:
The Java® Virtual Machine Specification
为什么要内存对齐?
内存对齐规则
对象内存布局
CPU和内存速度对比