我有一个使用lein run运行良好的clojure项目,但是lein uberjar的结果是
java.lang.RuntimeException: Method code too large!, compiling:(some_file.clj:1:1)同样的项目。我可以使用一个包含2000多个条目的大型向量来跟踪它,该向量定义如下所示:
(def x
[[1 :qwre :asdf]
[2 :zxcv :fafa]
...
])当从该向量中删除足够多的条目时,lein uberjar将无问题地编译。我如何使uberjar完成它的工作,将所有条目保留在向量中?
注:当将x更改为常数a la (def ^:const x时,lein run也会抛出一个太大的方法!错误。顺便说一句,这个错误发生在使用x的地方,所以如果不使用这个常量,只定义它就可以了。
发布于 2018-04-25 08:55:29
Java中方法的大小有一个64 in的限制。在您的例子中,创建大向量文字的方法似乎超过了这个限制。
实际上,您可以自己检查它,使用一个名为clj-java-decompiler的高级库。下面是一个使用boot的简短示例
(set-env!
:dependencies '[[com.clojure-goes-fast/clj-java-decompiler "0.1.0"]])
(require '[clj-java-decompiler.core :as d])
(d/decompile-form
{}
[[1 :qwre :asdf]
[2 :zxcv :fafa]
[3 :zxcv :fafa]])
;; ==> prints:
;;
;; // Decompiling class: cjd__init
;; import clojure.lang.*;
;;
;; public class cjd__init
;; {
;; public static final AFn const__10;
;;
;; public static void load() {
;; const__10;
;; }
;;
;; public static void __init0() {
;; const__10 = (AFn)Tuple.create((Object)Tuple.create((Object)1L, (Object)RT.keyword((String)null, "qwre"), (Object)RT.keyword((String)null, "asdf")), (Object)Tuple.create((Object)2L, (Object)RT.keyword((String)null, "zxcv"), (Object)RT.keyword((String)null, "fafa")), (Object)Tuple.create((Object)3L, (Object)RT.keyword((String)null, "zxcv"), (Object)RT.keyword((String)null, "fafa")));
;; }
;;
;; static {
;; __init0();
;; Compiler.pushNSandLoader(RT.classForName("cjd__init").getClassLoader());
;; try {
;; load();
;; Var.popThreadBindings();
;; }
;; finally {
;; Var.popThreadBindings();
;; }
;; }
;; }
;; 如您所见,有一个方法__init0为向量文字创建实际的Java对象。如果向量中有足够的元素,则该方法的大小很容易超过64 of的限制。
我认为,在您的例子中,解决这个问题的最简单的方法是将向量放到文件中,然后slurp+读取这个文件。就像这样:
文件vector.edn
[[1 :qwre :asdf]
[2 :zxcv :fafa]
...
]然后在你的代码中:
(def x (clojure.edn/read-string (slurp "vector.edn"))发布于 2018-04-25 03:07:26
在您的情况下,它会在调用delay时将值包装起来使其在第一次使用时被计算吗?
方法在java类文件中的大小是有限制的,Clojure中的每个顶级表单(通常)都会生成一个类。
要解决这个问题,安排生成和存储常量是很有用的:
如果您使用一个未来或制作一个回忆录函数来获取数据,您将在程序启动时计算它,并将其存储在内存中而不是类文件中。
如果将其放在资源目录中,它将不受大小限制,并且仍然可以在编译时进行计算。
如果禁用AOT编译,那么类限制将永远不会被击中,因为它将在程序启动时在加载时进行计算。
发布于 2018-04-25 03:08:09
事实证明,提前编译是lein run和lein uberjar之间的区别,因为我的project.clj包含(默认)行。
:profiles {:uberjar {:aot :all}})当我移除:aot :all时,uberjar结束时没有抱怨--但也没有aot--编译。所以我想我需要关闭aot,或者想办法把它限制到排除这个向量。
但是我希望能够拥有这个--尽管是巨大的--向量“文字”,并且仍然编译所有的东西。但是,也许将这个巨大的向量分解成一个数据文件(在启动时读取)也不是什么好主意。这样我就可以将:aot :all设置保持原样。
https://stackoverflow.com/questions/50013231
复制相似问题