对单个元素列表使用java.util.List的开销是多少?
我有一个内存键值存储(大小可能高达1GB),将对单个元素列表使用java.util.List的开销是多少?,java,list,collections,Java,List,Collections,我有一个内存键值存储(大小可能高达1GB),将String映射到String。 到目前为止,它已实现为Map 但是,有一种罕见的情况需要映射到字符串列表,因此需要将其更改为map 由于这不是一个常见的情况(可能小于%1),我正在讨论是否将这些用例划分为两个不同的映射 有没有人知道,与直接使用String对象相比,映射中的所有列表都只有一个元素,这会带来多大的开销(内存占用和CPU) 谢谢 可能性(按增加记忆足迹的顺序): Map Map=newhashmap();//串联字符串值 列表获取(字符
String
映射到String
。
到目前为止,它已实现为Map
但是,有一种罕见的情况需要映射到字符串列表,因此需要将其更改为map
由于这不是一个常见的情况(可能小于%1),我正在讨论是否将这些用例划分为两个不同的映射
有没有人知道,与直接使用String
对象相比,映射中的所有列表都只有一个元素,这会带来多大的开销(内存占用和CPU)
谢谢 可能性(按增加记忆足迹的顺序):
Map Map=newhashmap();//串联字符串值
列表获取(字符串键){
返回Arrays.asList(map.getOrDefault(键“”).split(“\f”);
}
Map Map=newhashmap();
私有静态最终字符串[]空=新字符串[0];
列表获取(字符串键){
返回Arrays.asList(map.getOrDefault(key,EMPTY));
}
Map Map=新的HashMap();//链表
列表获取(字符串键){
返回map.get(key);
}
(只是示例代码。我没有很好地处理空字符串。)
正如其他人所说,测量空间和速度。同时考虑<代码> SET/COM>作为更优化的数据结构,而不是<代码>列表< /代码>。考虑<代码>集合。Stutelon列表(“…”)和<代码> EMPTyList](< /代码> < /P>)
如果字符串主要是拉丁-1,则java 9使用更紧凑的字节数组(而不是java 8)。 对于大字符串,可以使用
GZipOutputStream
压缩到byte[]
最后一种选择是耗尽
java-Xmx
和物理内存:使用数据库,正如其他人已经建议的那样,只有通过测量,才能得到明确的答案(对于给定的机器/JVM组合)。但至少可以预测一些结果
除了Joop的建议之外,我还可以想象一些不同的方法:
- 使用简单明了的
,使用Map
或类似的通用列表,然后您会得到一个额外的(相当胖的)包装器对象,包括每个映射条目的字符串数组(可能是128字节)。实现是开箱即用的,但会浪费相当多的内存ArrayList
- 使用
,并确保将单个字符串值包装在映射
或类似的紧凑结构中。然后,每个字符串将获得一个额外的包装器对象(16到32字节)。开销较小,但在插入单个字符串时需要特殊处理Collections.singletonList()
- 使用两个映射,一个
用于单个字符串,一个Map
用于多字符串大小写。实际上没有开销,但在插入条目和查询/迭代映射时都需要特殊处理Map
- Joop的串联字符串解决方案将两个或多个
实例压缩为一个更长的String
,从而消除了它们各自的开销。这甚至会导致“负”开销,但在插入条目以及查询/迭代映射时都需要特殊处理。在检索条目时,String
拆分将消耗少量额外的运行时间,即使对于单个字符串的情况也是如此。[虽然字符串
String.split()
现在,选择权在你。测量它。决定这是否是你可以承担的成本。我将创建自己的
类
,它可以是,例如,实现的Iterable
。Java是一种语言,您可能想知道与某个已知的编译器或解释器(或两者的混合体,如Oracle JVM)一起使用时的开销。“开销”一词实际上并不适用于源代码,不管是哪种语言。这就像问“这个句子写在这里有多快?”。至于你问题的隐含意义——我同意@BoristheSpider——你需要测量才能知道,否则称为“分析”。散列遗漏的成本非常低。您可以为多个条目创建一个单独的映射,并首先检查该映射。您可以问问自己性能有多重要(在访问此数据结构时)。我想说,99%的情况下,最好是押注于可读代码,而不是执行代码。所以我的建议是使用Guava的MulitMap实现。然后用两个数据结构来表示一个概念。不过,请回答您的问题。使用Map
创建额外级别的间接寻址,因此几乎肯定会在访问单个项目列表时触发缓存未命中(在CPU一级缓存中)。因此,成本至少会降低。
Map<String, String> map = new HashMap<>(); // Concatenated string values
List<String> get(String key) {
return Arrays.asList(map.getOrDefault(key, "").split("\f"));
}
Map<String, String[]> map = new HashMap<>();
private static final String[] EMPTY = new String[0];
List<String> get(String key) {
return Arrays.asList(map.getOrDefault(key, EMPTY));
}
Map<String, List<String>> map = new HashMap<>(); // LinkedList
List<String> get(String key) {
return map.get(key);
}