Java中的UUIDs是否像字符串一样被实习?如果没有,我应该尝试回收UUID对象以最小化RAM使用吗?
我使用UUID作为数据库主键的数据类型&外键列。所以这意味着许多行重复使用UUID来共享外键值。
因此,在从数据库中检索行时,是否应该检查每个UUID是否重复,如果是重复的,请使用原始对象引用?或者这是否已经代表我完成,类似于Strings are interned?
… // common JDBC code
UUID id = null ;
while (rs.next()) {
UUID idFresh = rs.getObject( 1 );
// Recycle the UUID object where possible.
id = ( ( null == id ) || idFresh.equals( id ) ) ? idFresh : id ; // If null or identical, use the existing object reference.
String name = rs.getString( 2 );
}
…
答案 0 :(得分:4)
快速查看java runtime source code表示UUID未被实习。
实习它们可能是一个坏主意,因为如果你要遍历一个大型数据库,UUID实习可能会导致JVM内存耗尽,原因只是因为它从未预测过它所见过的任何UUID。
此外,实习UUID并没有多大好处,因为
它们没有占用太多空间(基本上只是UUID的128位值存储为一对long
)
UUID比较和哈希码计算很便宜。
(String
实习的最大好处之一是字符串的哈希码只计算一次,这有点令人担忧因为它的计算可能稍贵。)
答案 1 :(得分:1)
UUID(以及字符串)不会自动进行重复数据删除。一般来说,这也是一个坏主意,因为新创建的UUID应该是唯一的,因此共享将不起作用。
当您引用字符串实习时,JVM将在特定情况下共享字符串,例如:
String x = "ab";
String y = "a" + "b";
assert x == y; // references are identical (x and y are shared)
然而,这些字符串可以在编译时解决。如果在运行时创建字符串或UUID,它将始终创建一个新对象。
在您的问题中,您描述了一个不同的场景。在这里,您正在从数据库中读取UUID。根据数据,可能有很好的共享UUID的机会,或者可能没有(例如,如果将UUID用作主键)。
id | name | country
1 | A | <UUID-1>
2 | B | <UUID-1>
3 | C | <UUID-2>
4 | D | <UUID-1>
5 | E | <UUID-1>
(请注意,从数据库或网络中读取UUID时,您不能假设UUID将进行重复数据删除。通常,您将收到相同值的副本。)
因此,如果您的数据如上所示,共享UUID是有意义的。但它会减少内存使用量吗?
UUID是一个包含两个long
个变量的对象。在64位JVM中,这将占用32个字节。如果您共享UUID,那么您只需支付32个字节一次,然后仅为参考支付8个字节。如果您使用compressed pointers,则引用将适合4个字节。
这个收益是否足够重要?这取决于您的具体应用。一般来说,我不会分享UUID。然而,我在一个应用程序上工作,共享UUID确实是一个改进。减少内存使用量是至关重要的,从完整对象到参考的减少是一种改进。
话虽如此,很少需要这种类型的优化。根据经验,我只会在UUID被大量共享的情况下这样做,并且不惜一切代价减少内存。否则,重复删除它们的CPU开销和代码中的额外复杂性通常是不值得的,或者更糟糕的是,甚至可能会降低应用程序的速度。
如果你决定对它们进行重复数据删除,你会怎么做?没有像String#intern
这样的内置函数,但您可以手动创建要进行重复数据删除的映射。根据您是要全局重复数据删除还是仅在当前函数调用中进行本地重复数据删除,您可以使用ConcurrentHashMap
或仅使用(非同步)HashMap
。
作为旁注,与您的问题没有直接关系,我提到了String#intern
,因为它是String API的一部分。但是,我强烈建议不要使用它,因为它是a huge performance bottleneck。自己进行重复数据删除会明显加快。