trove4j:大数据下的轻量Java Collections库

之前的blog有提到,Java自带的Class和Collections都很费内存。如果你像我一样,需要加载大量的数据到内存,很在乎内存的开销,那么可以试一试trove4j

trove4j最棒的地方在于,它提供了支持原生数据类型(比如int, double, boolean)的Collections。而JDK自带的Collections必须存放对象(比如Integer, Double, Boolean)。

具体有多好?我尝试做了个实验
分别用HashSet<Integer>和trove4j中的TIntHashSet加载10000000个int值,然后用:
$jmap -histo PID
查看内存的占用情况。
1千万个int的数据大小 = 4 bytes * 10000000 ~= 40 MB。当然,因为是放入hashset中,肯定会有一些额外的索引开销。

采用HashSet<Integer>, 内存开销如下:
num     #instances         #bytes  class name
———————————————-
1:      10000154      480007392  java.util.HashMap$Entry     //1千万个Map.Entry对象
2:      10000004      240000096  java.lang.Integer                  //1千万个Integer对象
3:                  28      134224672  [Ljava.util.HashMap$Entry;

因为JDK中的HashSet<Integer>是用HashMap<Integer, Object>实现的,所以,每个int值放入Map中都需要构造一个Map.Entry对象。
很容易计算得到,每个Map.Entry对象:
size = 480007392 / 10000154 = 48 bytes
另外,int需要转换成Integer才能放入,每个Integer对象:
szie = 240000096 / 10000004 = 24 bytes
所以,一个int值放入HashSet中,至少就需要消耗 48 + 24 = 72 bytes。
再算上其他开销,这1千万int差不多消耗了内存 854 MB,差不多是原始大小的 854 / 40 = 21.35倍。

再看看TIntHashSet的表现:
 num     #instances         #bytes  class name
———————————————-
1:           422      107157392  [I          // int[]   数组
2:           505        26435816  [B        // byte[] 数组

很明显,TIntHashSet没有构造任何的Map.Entry,而且没有采用Integer对象来存储int值,它的数据结构是一堆的int[]数组和byte[]数组。
整个开销差不多 107 + 26 ~= 133 MB,是原始大小的大概3.3倍。只有HashSet<Integer>占用内存的1/6。
节约开销非常的明显。

其实,我还简单测试了Guava中的ImmutableSet,开销大概比HashSet能够减少1/5,但是ImmutableSet本身在使用上也有限制,而且还不如TIntHashSet节约。

Big Data时代,将大数据量加载到内存中会越来越常见,像trove4j这种memory sensitive的库会更加有用。

——————————-  更多实验数据  —————————————-

500万int数据:

Collections HashSet:
num     #instances         #bytes  class name
———————————————-
1:       5000154      240007392      java.util.HashMap$Entry
2:       5000004      120000096      java.lang.Integer
3:                 28       67115808       [Ljava.util.HashMap$Entry;
4:               422        1770392        [I

Trove TIntSet:
num     #instances         #bytes  class name
———————————————-
1:           422       53988552  [I
2:           505       13265824  [B

300万int数据:

Collections HashSet:
num     #instances         #bytes  class name
———————————————-
1:       3000154      144007392    java.util.HashMap$Entry
2:       3000004       72000096     java.lang.Integer
3:                 28       33561376     [Ljava.util.HashMap$Entry;
4:               420        1130664      [I

Trove TIntSet:
 num     #instances         #bytes  class name
———————————————-
1:           422       27512264     [I
2:           505         6680824     [B

Advertisements
相册 | 此条目发表在Java分类目录,贴了标签。将固定链接加入收藏夹。

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s