从Java代码到Java堆

优化应用程序代码的内存使用并不是一个新主题,但是人们通常并没有很好地理解这个主题。本文将简要介绍 Java 进 程的内存使用,随后深入探讨您编写的 Java 代码的内存使用。最后,本文将展示提高代码内存效率的方法,特别强调了 HashMap 和 ArrayList 等 Java 集合的使用。

背景信息:Java 进程的内存使用

通过在命令行中执行 java 或者启动某种基于 Java 的中间件来运行 Java 应用程序时,Java 运行时会创建一个操作系统进程,就像您运行基于 C 的 程序时那样。实际上,大多数 JVM 都是用 C 或者 C++ 语言编写的。作为操作系统进程,Java 运行时面临着与其他进程完 全相同的内存限制:架构提供的寻址能力以及操作系统提供的用户空间。

架构提供的内存寻址能力依赖于处理器的 位数,举例来说,32 位或者 64 位,对于大型机来说,还有 31 位。进程能够处理的位数决定了处理器能寻址的内存范围 :32 位提供了 2^32 的可寻址范围,也就是 4,294,967,296 位,或者说 4GB。而 64 位处理器的可寻址范围明显增大: 2^64,也就是 18,446,744,073,709,551,616,或者说 16 exabyte(百亿亿字节)。

处理器架构提供的部分可寻址 范围由 OS 本身占用,提供给操作系统内核以及 C 运行时(对于使用 C 或者 C++ 编写的 JVM 而言)。OS 和 C 运行时占 用的内存数量取决于所用的 OS,但通常数量较大:Windows 默认占用的内存是 2GB。剩余的可寻址空间(用术语来表示就 是用户空间)就是可供运行的实际进程使用的内存。

对于 Java 应用程序,用户空间是 Java 进程占用的内存,实 际上包含两个池:Java 堆和本机(非 Java)堆。Java 堆的大小由 JVM 的 Java 堆设置控制:-Xms 和 -Xmx 分别设置最 小和最大 Java 堆。在按照最大的大小设置分配了 Java 堆之后,剩下的用户空间就是本机堆。图 1 展示了一个 32 位 Java 进程的内存布局:

图 1. 一个 32 位 Java 进程的内存布局示例

在 图 1 中,可寻址范围总共有 4GB,OS 和 C 运行时大约占用了其中的 1GB,Java 堆占用了将近 2GB,本机堆占用了其他部分。请注意,JVM 本身也要占用内存,就 像 OS 内核和 C 运行时一样,而 JVM 占用的内存是本机堆的子集。

Java 对象详解

在您的 Java 代码使用 new 操作符创建一个 Java 对象的实例时,实际上分配的数据要比您想的多得多。例如,一个 int 值与一个 Integer 对象 (能包含 int 值的最小对象)的大小比率是 1:4,这个比率可能会让您感到吃惊。额外的开销源于 JVM 用于描述 Java 对 象的元数据,在本例中也就是 Integer。

根据 JVM 的版本和供应的不同,对象元数据的数量也各有不同,但其中通 常包括:

类:一个指向类信息的指针,描述了对象类型。举例来说,对于 java.lang.Integer 对象,这是 java.lang.Integer 类的一个指针。

标记:一组标记,描述了对象的状态,包括对象的散列码(如果有),以及对象的形状(也就是说,对象是否是数组) 。

锁:对象的同步信息,也就是说,对象目前是否正在同步。

对象元数据后紧跟着对象数据本身,包括对象实例中存储的字段。对于 java.lang.Integer 对象,这就是一个 int。

如果您正在运行一个 32 位 JVM,那么在创建 java.lang.Integer 对象实例时,对象的布局可能如图 2 所示:

图 2. 一个 32 位 Java 进程的 java.lang.Integer 对象的布局示例

如 图 2 所示,有 128 位的数据被占用,其 中用于存储 int 值的为 32 位,而对象元数据占用了其余的 96 位。

Java 数组对象详解

数组对象(例如 一个 int 值数组)的形状和结构与标准 Java 对象相似。主要差别在于数组对象包含说明数组大小的额外元数据。因此, 数据对象的元数据包括:

类:一个指向类信息的指针,描述了对象类型。举例来说,对于 int 字段数组,这是 int[] 类的一个指针。

标记:一组标记,描述了对象的状态,包括对象的散列码(如果有),以及对象的形状(也就是说,对象是否是数组) 。

锁:对象的同步信息,也就是说,对象目前是否正在同步。

大小:数组的大小。

图 3 展示了一个 int 数组对象的布局示例:

图 3. 一个 32 位 Java 进程的 int 数组对象的布局示例

如 图 3 所示, 有 160 位的数据用于存储 int 值内的 32 位数据,而数组元数据占用了其余 160 位。对于 byte、int 和 long 等原语, 从内存的方面考虑,单项数组比对应的针对单一字段的包装器对象(Byte、Integer 或 Long)的成本更高。

时间: 2024-08-28 05:32:54

从Java代码到Java堆的相关文章

诊断 Java 代码: 提高 Java 代码的性能 尾递归转换能加快应用程序的速度,但不是所有的 JVM 都会做这种转换

简介: 很多算法用尾递归方法表示会显得格外简明.编译器会自动把这种方法转换成循环,以提高程序的性能.但在 Java 语言规范中,并没有要求一定要作这种转换,因此,并不是所有的 Java 虚拟机(JVM)都会做这种转换.这就意味着在 Java 语言中采用尾递归方法将导致巨大的内存占用,而这并不是我们期望的结果.Eric Allen 在本文中阐述了动态编译将会保持语言的语义,而静态编译则通常不会.他说明了为什么这是一个重要问题,并提供了一段代码来帮助判断您的即时(JIT)编译器是否会在保持语言语义的

java代码-用Java代码实现字母的自增

问题描述 用Java代码实现字母的自增 自增规则,从A-Z,AA-AZ,BA-BZ,... 哪位高手能指点一下. 解决方案 public class Main { public static void main(String[] args) { String s = " ABCDEFGHIGKLMNOPQRSTUVWXYZ"; for (int j = 0; j < 26; j++) { for (int i = 1; i < 26; i++) { System.out.p

诊断Java代码: 提高Java代码的性能

很多算法用尾递归方法表示会显得格外简明.编译器会自动把这种方法转换成循环,以提高程序的性能.但在 Java 语言规范中,并没有要求一定要作这种转换,因此,并不是所有的 Java 虚拟机(JVM)都会做这种转换.这就意味着在 Java 语言中采用尾递归方法将导致巨大的内存占用,而这并不是我们期望的结果.Eric Allen 在本文中阐述了动态编译将会保持语言的语义,而静态编译则通常不会.他说明了为什么这是一个重要问题,并提供了一段代码来帮助判断您的即时(JIT)编译器是否会在保持语言语义的同时做尾

java代码-用Java做了一个记忆翻盘游戏,但是不知道怎么加进声音

问题描述 用Java做了一个记忆翻盘游戏,但是不知道怎么加进声音 10C 求大神帮忙,才学了两个月,用Java弄了一个记忆翻盘游戏,游戏界面已经可以呈现出来,但是不知道怎么加进声音,最好能提供一下代码,拜托拜托- 解决方案 import javax.sound.midi.*;try {Sequencer sequencer = MidiSystem.getSequencer();sequencer.open();Sequence sequence = MidiSystem.getSequence

java代码 类-java中可以直接对类名进行引用吗?

问题描述 java中可以直接对类名进行引用吗? 我是初学者,最近看到了下面的代码: public class ActivityCollector { public static List<Activity> activities = new ArrayList<Activity>(); public static void addActivity(Activity activity) { activities.add(activity); } public static void

java代码-将java的class存入数据库,这个叫什么?如何实现?

问题描述 将java的class存入数据库,这个叫什么?如何实现? 目前经理要求在做一个业务统计的程序,他要求把写好的类存入数据库,类比如是org.com.test.HelloDate,数据库就是存放这个,然后由启动统计的主方法调用数据库存放的这个类来实现统计,这个究竟在java里是什么原理?如何实现呢?求给位高手帮忙解答 解决方案 Java反射Reflect机制啊. ClassLoader loader = Thread.currentThread().getContextClassLoade

java代码-用java实现从不同服务器上下载的table进行比较与覆盖

问题描述 用java实现从不同服务器上下载的table进行比较与覆盖 图片如果看不到,请进我空间的相册查看.java:从不同的服务器上下载test table,然后将其中一个服务器的table覆盖到另外一个服务器上的table,要求table里面的属性能够更改(如string->int),保留原有的数据,本人菜鸟级别,第一次配到这样的难题,求各位大神给代码提示

java代码-求java识别三角形,圆形,方形的具体代码。

问题描述 求java识别三角形,圆形,方形的具体代码. 图片有背景,中间有图形,要求对图片进行分析,识别出是哪一种图形..初学者,求详细代码研究研究~谢谢..

Rational Rose正逆向工程(类图转Java代码,Java代码转类图)

 一,正向工程     1.设置默认语言为Java,Tools->Options->Notation->default:选择Java.         2.设置环境变量ClassPath,Tools->Java/j2ee->Project   Specification->ClassPath:具体路径设置为正向工程生成java文件要保存的目录,一般为项目的src目录.         3.打开设计好的类图,选中要生成的Java文件的类,然后通过Tools->J