一个java.util.Date对象占用多少字节的内存?

20

我需要存储大量日期数据(可能足够大以至于堆空间的使用量是一个问题,因此请不要谈论过早优化),我想知道是否有必要使用某种原始表示形式来代替java.util.Date(或其他现有的Date类)。 我知道我可以进行一些分析来尝试一下,但是是否有人知道单个Date对象使用多少字节的内存?


2
你可以将日期存储为长整型原始数据类型,需要时再转换为日期吗? - BacMan
7个回答

18

我的第一反应是,Date类所占用的内存开销非常小。检查源代码后发现,该类只包含一个实例字段(名为“milliseconds”的long类型)。这意味着日期对象的大小是一个long类型加上一个Object实例的大小,也就是非常小。

然后我找到了这段代码,它创建了数千个对象来确定对象的大小。它指出java.util.Date对象的大小为32个字节。与仅将日期存储为long相比(它的内部实际上就是这样实现的)——long占8个字节,因此你需要为方便地拥有日期对象付出四倍的代价。

然而,创建对象的开销并不是非常高。因此,如果你真的很担心空间问题,那么就将日期存储为long型,并在需要时创建一个Date对象。


这是因为Date只是long的包装对象。我快速查看了API,发现所有使Date对象有用的内容都已被弃用,并已被Calendar替代。 - Dunes
@Dunes,Calendar的缺点是它要贵得多。我建议你只在需要时使用日历。 - Peter Lawrey
膨胀是一个相对的术语。Java支持对象的垃圾回收,这至少意味着对象必须存储其ID以及该ID在内存中的当前空间。该对象还需要引用其类型。我现在可能没有考虑到更多的内容,但是如果您不想要对象提供的功能,则此类存储仅会导致膨胀。如果您不想要这些功能,请分配一个长整型数组并完成它。 - Edwin Buck
@Peter 关于日历的建议很好。这也是我想表达的内容。虽然也许我没有表达清楚。 - Dunes
3
@Peter,确实只有当您拥有很多这些对象时才真正重要,但我非常明确地表明我确实拥有很多这些对象。在我的应用程序中,我们已经遇到了许多开发人员使用了您所描述的“内存便宜”哲学的情况,结果却让我们后悔不已。此外,客户可能希望在不需要购买新计算机的情况下使用我们的软件(他们可能有一个限制其潜在堆大小的32位操作系统)。 - Michael McGowan
显示剩余5条评论

9

使用原始类型long?

它不是一个对象,所以占用更少的空间,日期可以表示为一个long值。当您想要存储日期并且使用更少的内存时,然后在Date和long之间进行相互转换。


使用原始长整型是我考虑的另一种选择。然而,我当时设想编写一堆自定义方法来执行Date已经完成的操作,而不是像你建议的那样根据需要创建Date对象。 - Michael McGowan
1
请确保使用'long'而不是'Long',否则您将无法获得所需的效益。 long类型的数据比Date类型的数据小约4倍。 - Peter Lawrey

3

如同这里所回答的:

回答这个问题最简单的方法是查看java.util.Date的源代码。

它只有两个非静态字段(Java 1.7.0_55):

private transient long fastTime;
private transient BaseCalendar.Date cdate;

long的内存大小为8字节,cdate是一个对象引用,其大小为4字节。因此总共占用12字节

如果实例化cdate可能需要额外的字节内存,但是如果你查看构造函数,有时它甚至不会被触及,在其他情况下,它将在构造函数结束时被null,因此最终结果也是12字节

这仅适用于创建一个Date。如果您对Date调用方法(例如Date.toString()),那么创建并将对象存储到cdate字段中,该对象不会被清除。因此,如果您在Date上调用某些方法,则其内存使用量将增加。

注意:在64位JVM上,对象引用可能为64位长,这种情况下,内存使用量将为16字节。

注意#2:还要注意,这仅是Date对象本身的内存使用量。很可能您会将其引用存储在其他类的数组、列表或字段中,这将需要额外的4个字节(或者在64位JVM上可能需要8个字节)。


3

1
我根据这里的规则http://www.javamex.com/tutorials/memory/object_memory_usage.shtml进行了手动计算,并检查了Java 7中Date对象的源代码以获取内存使用情况。
Object overhead: 8 bytes => 8 bytes
+ 1 long fastTime: 8 bytes => 16 bytes
+ 1 reference cdate: 4 bytes => 20 bytes
Rounded up to nearest multiple of 8 => 24 bytes

也许我在计算或其他答案中使用的工具中漏掉了什么,导致得出32的结果包括对日期本身的引用?

1
如果真的是日期而不是日期和时间戳,你甚至可以使用整数: 20110113

0

java.util.Date对象可以用一个长整型值来表示,而长整型值是8个字节的,范围为-2^63到(2^63)-1


我知道long类型占用8个字节,可以用来表示日期,但我不确定java.util.Date是否这样做。此外,对象不是原始类型可能意味着它更大,即使支持long类型。 - Michael McGowan
@Micheal,你说得对,日期对象可能比8字节大,但不是因为它在内部使用了不同的日期表示方式,而是因为它还包含了其他几个对象。请查看Date类的实现。long足够大,可以确保精确地保存时间,不仅是毫秒,甚至可以保存纳秒级别的时间。 - fmucar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接