首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >lein uberjar导致“方法代码太大了!”

lein uberjar导致“方法代码太大了!”
EN

Stack Overflow用户
提问于 2018-04-25 02:35:41
回答 3查看 560关注 0票数 2

我有一个使用lein run运行良好的clojure项目,但是lein uberjar的结果是

代码语言:javascript
复制
java.lang.RuntimeException: Method code too large!, compiling:(some_file.clj:1:1)

同样的项目。我可以使用一个包含2000多个条目的大型向量来跟踪它,该向量定义如下所示:

代码语言:javascript
复制
(def x
  [[1 :qwre :asdf]
   [2 :zxcv :fafa]
   ...
])

当从该向量中删除足够多的条目时,lein uberjar将无问题地编译。我如何使uberjar完成它的工作,将所有条目保留在向量中?

注:当将x更改为常数a la (def ^:const x时,lein run也会抛出一个太大的方法!错误。顺便说一句,这个错误发生在使用x的地方,所以如果不使用这个常量,只定义它就可以了。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-04-25 08:55:29

Java中方法的大小有一个64 in的限制。在您的例子中,创建大向量文字的方法似乎超过了这个限制。

实际上,您可以自己检查它,使用一个名为clj-java-decompiler的高级库。下面是一个使用boot的简短示例

代码语言:javascript
复制
(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

代码语言:javascript
复制
[[1 :qwre :asdf]
 [2 :zxcv :fafa]
 ...
 ]

然后在你的代码中:

代码语言:javascript
复制
(def x (clojure.edn/read-string (slurp "vector.edn"))
票数 3
EN

Stack Overflow用户

发布于 2018-04-25 03:07:26

在您的情况下,它会在调用delay时将值包装起来使其在第一次使用时被计算吗?

方法在java类文件中的大小是有限制的,Clojure中的每个顶级表单(通常)都会生成一个类。

要解决这个问题,安排生成和存储常量是很有用的:

  • 在运行时计算内存中的
  • 在资源目录中,可以在运行时读取它们。
  • 不要通过未预先编译类文件来生成类文件,这将在程序开始时生成数据。

如果您使用一个未来或制作一个回忆录函数来获取数据,您将在程序启动时计算它,并将其存储在内存中而不是类文件中。

如果将其放在资源目录中,它将不受大小限制,并且仍然可以在编译时进行计算。

如果禁用AOT编译,那么类限制将永远不会被击中,因为它将在程序启动时在加载时进行计算。

票数 0
EN

Stack Overflow用户

发布于 2018-04-25 03:08:09

事实证明,提前编译是lein runlein uberjar之间的区别,因为我的project.clj包含(默认)行。

代码语言:javascript
复制
:profiles {:uberjar {:aot :all}})

当我移除:aot :all时,uberjar结束时没有抱怨--但也没有aot--编译。所以我想我需要关闭aot,或者想办法把它限制到排除这个向量。

但是我希望能够拥有这个--尽管是巨大的--向量“文字”,并且仍然编译所有的东西。但是,也许将这个巨大的向量分解成一个数据文件(在启动时读取)也不是什么好主意。这样我就可以将:aot :all设置保持原样。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50013231

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档