《零基础学 Java》 FAQ 之 9-Java 里的各种数据类型占用多少内存空间
来自 @谭低调 同学的问题:引用占用多少内存?
@谭低调 同学在“34 | 认识引用类型(下)”里问了这么一个问题:
请问老师,Merchandise m1 这个引用类型变量是多大呢?或者说为了存储实例的地址,需要给 m1 多大的内存?
简单版
简单来说,基本数据类型都是按照最小的、值域规定的范围使用的内存。比如 byte,boolean 都是 1 个字节。int 和 float 是 4 个字节,long 和 double 是 8 个字节
但是对于引用类型来说,32 位的机器,引用类型要占用 32 个 bit,也就是 4byte。64 位的,要占用 8 个 byte。但是对于 64 位的虚拟机,可以开启引用压缩选项,让它也只占用 4 个 byte。
如果有兴趣,可以看下的啰嗦版。
Java 程序员需要关心数据类型对内存的占用情况吗?
Java 用跑在虚拟机里,并且有一个严格得虚拟机规范,就是让程序员可以在不知道这这些底层细节的情况下,也能好好安心写程序。这个目标是非常正确的,甚至是对 Java 的成功都是非常关键的。
软件的世界就是这样,一个层次解决一个层次的问题,既然 JVM 已经屏蔽了底层细节信息,上层的 Java 代码就可以不必关心更下层的细节了。
但是不必了解,并非是了解了没用。不了解也能写出好代码,了解了之后在某些情况下可以写出更好的代码。尤其是在对程序关键点的数据结构设计和预估程序总体内存占用情况时,会有帮助。
JVM 规范没规定
JVM 规范从来没有规定每种数据类型占用多大的内存。它只是给出了每种数据类型的值域。严谨的不要不要的。既然规范没有说,那么肯定占用的内存就可以是不固定的喽。具体占用多少,得看规范得实现。
那么具体到某种实现,就是固定得了么?
JDK 实现:看位数
很多年前,主流的操作系统和 CPU 都是 32 位的。什么意思呢,就是 CPU 的指令能够处理的数,都是 32 位的,包括内存寻址,也是 32 位的。所以 32 位的系统下,可以使用的内存不能超过 4G,因为 32 位的寻址空间只能表示这么大的内存地址范围。
后来出现了 64 位的操作系统和 CPU,寻址空间和 CPU 操作数都是 64 位了。Java 进程也是操作系统上的应用程序。我们知道程序都分 64 位版和 32 位版,JDK 也一样。
对于栈和堆的上的数据,可以分配的有基本数据类型和引用类型。
基本数据类型很简单,大部分 JVM 都会按照值域来分配最小的需要的内存,这个我们在前面已经介绍过。
引用类型:磨人的小妖精
引用类型作为一种非常特殊的类型,和内存寻址相关。所以,JDK 底层实现上一般会使用 C/C++的 pointer 来封装成 Java 里的引用。那么它占用的内存就是和 JDK 是 32 位还是 64 位有关。如果是 64 位的 JDK,那么在上述的内存区域里,引用类型都是占用 8 个字节的内存。32 位的 JDK 就占 4 个字节。
如果引用类型这么简单直接,就不是磨人的小妖精了。引用类型毕竟太多,而且绝大多数情况下用不了这么大空间,太浪费。所以 Oracle 的 JDK 就针对这种情况,开发了一个压缩指针的功能,主要针对 Java 内存堆小于 32g 的情况。这个 JVM 参数是-XX:+UseCompressedOops
下面是 Oracle 官方文档对这个参数的说明:
Enables the use of compressed pointers (object references represented as 32 bit offsets instead of 64-bit pointers) for optimized 64-bit performance with Java heap sizes less than 32gb.
引自 https://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
这篇文章来自极客时间推出的《零基础学Java》中的 FAQ。除了在每节视频课下方回答大家的问题之外,针对大家提出的优质问题或者普遍问题,如果需要更大篇幅的文章解答,则会在 FAQ 中以文章的方式给出回答。带你零基础入门,夯实 Java,课程地址:https://time.geekbang.org/course/intro/181
版权声明: 本文为 InfoQ 作者【臧萌】的原创文章。
原文链接:【http://xie.infoq.cn/article/66d57eae826f8498026346bd0】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论