[英]Large size of HashSet throwing StackOverflow Error
我有 81K 长 object 记录,我正在尝试将其存储在 HashSet 中。 我的代码片段如下所示:
private static HashSet<Long> hashSet = new HashSet<>(Arrays.asList(*81K records*));
编译时给了我StackOverflow Error
。 我不明白为什么这里只有 81K 记录有问题? 解决方案表示赞赏。
Java 版本。 :
openjdk version "1.8.0_322"
OpenJDK Runtime Environment Corretto-8.322.06.1 (build 1.8.0_322-b06)
OpenJDK 64-Bit Server VM Corretto-8.322.06.1 (build 25.322-b06, mixed mode)
堆栈跟踪:
[javac]
[javac]
[javac] The system is out of resources.
[javac] Consult the following stack trace for details.
[javac] java.lang.StackOverflowError
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
[javac] at com.sun.tools.javac.code.Type.map(Type.java:220)
Type
的第 220 行:
208 /**
209 * Return the least specific subtype of t that starts with symbol
210 * sym. If none exists, return null. The least specific subtype
211 * is determined as follows:
212 *
213 * <p>If there is exactly one parameterized instance of sym that is a
214 * subtype of t, that parameterized instance is returned.<br>
215 * Otherwise, if the plain type or raw type `sym' is a subtype of
216 * type t, the type `sym' itself is returned. Otherwise, null is
217 * returned.
218 */
219 public Type asSub(Type t, Symbol sym) {
220 return asSub.visit(t, sym);
221 }
222 // where
223 private final SimpleVisitor<Type,Symbol> asSub = new SimpleVisitor<Type,Symbol>() {
The specific issue is that Java type inference cannot deal with such a long constant -- as reflected by the stack overflow you got in the Java compiler itself -- but it's also the case that Java bytecode format does not allow you to put such large amounts数据到您的源代码。 方法代码的最大大小——这是 Java 在幕后初始化它的方式——是 64KB; 单独存储 81K long
常量是这个限制的 10 倍。
您当然可以将此数据存储到HashSet
等中,但您必须在运行时从文件中加载它。
HashSet
在这里无关紧要。 有问题的部分是具有 81,000 个元素的Arrays.asList
的可变参数调用。
要重现该问题,我们可以使用以下代码
class Tmp {
static final String ARGUMENTS = "<<INSERT ARGUMENTS HERE>>";
static final List<String> TEMPLATE = Arrays.asList(
"import java.util.Arrays;",
"import java.util.List;",
"",
"class Tmp {",
" static final List<Integer> L = Arrays.asList(",
ARGUMENTS,
" );",
"}");
public static void main(String[] args) throws IOException {
Path p = Files.createTempFile("Test", ".java");
Files.write(p, () -> TEMPLATE.stream()
.flatMap(line -> line.equals(ARGUMENTS)? varargsArgument(): Stream.of(line))
.iterator());
JavaCompiler c = ToolProvider.getSystemJavaCompiler();
c.run(System.in, System.out, System.err, p.toString());
}
static Stream<CharSequence> varargsArgument() {
return IntStream.range(0, 8100).mapToObj(i -> IntStream.range(0, 10)
.mapToObj(j -> i * 10 + j + (i < 8099 || j < 9? ", ": ""))
.collect(Collectors.joining()));
}
}
使用OpenJDK 8 ,它产生
java.lang.StackOverflowError
at com.sun.tools.javac.code.Type.map(Type.java:220)
…
在最近的 JDK 上,例如JDK 12 ,它产生
/tmp/Test14992292170362927520.java:6: error: code too large
static final List<Integer> L = Arrays.asList(
^
表明即使编译器错误已修复,此类代码也无法编译。
此类数据量应作为嵌入式资源包含在内,您在启动时读取一次。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.