Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/396.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
对单个元素列表使用java.util.List的开销是多少?_Java_List_Collections - Fatal编程技术网

对单个元素列表使用java.util.List的开销是多少?

对单个元素列表使用java.util.List的开销是多少?,java,list,collections,Java,List,Collections,我有一个内存键值存储(大小可能高达1GB),将String映射到String。 到目前为止,它已实现为Map 但是,有一种罕见的情况需要映射到字符串列表,因此需要将其更改为map 由于这不是一个常见的情况(可能小于%1),我正在讨论是否将这些用例划分为两个不同的映射 有没有人知道,与直接使用String对象相比,映射中的所有列表都只有一个元素,这会带来多大的开销(内存占用和CPU) 谢谢 可能性(按增加记忆足迹的顺序): Map Map=newhashmap();//串联字符串值 列表获取(字符

我有一个内存键值存储(大小可能高达1GB),将
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
    ,使用
    ArrayList
    或类似的通用列表,然后您会得到一个额外的(相当胖的)包装器对象,包括每个映射条目的字符串数组(可能是128字节)。实现是开箱即用的,但会浪费相当多的内存

  • 使用
    映射
    ,并确保将单个字符串值包装在
    Collections.singletonList()
    或类似的紧凑结构中。然后,每个字符串将获得一个额外的包装器对象(16到32字节)。开销较小,但在插入单个字符串时需要特殊处理

  • 使用两个映射,一个
    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);
}