首页 > 解决方案 > springboot LaunchedURLClassLoader throws error class超过了JVM支持的最大类大小(常量池太大)

问题描述

我有一个遗留应用程序,其中一个 java 文件有大约 280000 行。我有一个用于 restful 服务的 spring boot 应用程序,其中一个服务调用这个巨大的 JAVA 文件。当我在没有 aspectjweaver 的情况下加载应用程序时,应用程序工作正常,但当我在 java 选项中指定 javaagent 时失败。我已经尝试过 JVM 堆,但它没有帮助。

以下是错误堆栈跟踪:

[LaunchedURLClassLoader@7cbd213e] error at MYCLASS.java::0 The class MYCLASS exceeds the maximum class size supported by the JVM (constant pool too big).
Aug 14, 2020 3:42:01 PM org.aspectj.weaver.tools.Jdk14Trace error
SEVERE: MYCLASS 
java.lang.RuntimeException: key not found in wovenClassFile
        at org.aspectj.weaver.WeaverStateInfo.findEndOfKey(WeaverStateInfo.java:408)
        at org.aspectj.weaver.WeaverStateInfo.replaceKeyWithDiff(WeaverStateInfo.java:364)
        at org.aspectj.weaver.bcel.LazyClassGen.getJavaClassBytesIncludingReweavable(LazyClassGen.java:711)
        at org.aspectj.weaver.bcel.BcelWeaver.getClassFilesFor(BcelWeaver.java:1448)
        at org.aspectj.weaver.bcel.BcelWeaver.weaveAndNotify(BcelWeaver.java:1410)
        at org.aspectj.weaver.bcel.BcelWeaver.weave(BcelWeaver.java:1188)
        at org.aspectj.weaver.tools.WeavingAdaptor.getWovenBytes(WeavingAdaptor.java:527)
        at org.aspectj.weaver.tools.WeavingAdaptor.weaveClass(WeavingAdaptor.java:363)
        at org.aspectj.weaver.loadtime.Aj.preProcess(Aj.java:121)
        at org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:54)
        at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
        at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:94)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        at java.lang.Class.getDeclaredConstructors0(Native Method)
        at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
        at java.lang.Class.getDeclaredConstructors(Class.java:2020)
        at com.fasterxml.jackson.databind.util.ClassUtil.getConstructors(ClassUtil.java:1162)
        at com.fasterxml.jackson.databind.introspect.AnnotatedCreatorCollector._findPotentialConstructors(AnnotatedCreatorCollector.java:101)
        at com.fasterxml.jackson.databind.introspect.AnnotatedCreatorCollector.collect(AnnotatedCreatorCollector.java:56)

标签: spring-bootrestaspectj

解决方案


AspectJ 转换原始字节码,向其中添加额外的指令和数据。所以你的怪物类——谁会写一个如此疯狂的大类而不以称自己为程序员为耻?- 只是变得太大了,因为它可能一开始就接近 JVM 每个类的大小限制。

你能做什么?好吧,这取决于情况:

  • 将类重构为更小的部分,使用自动化测试覆盖重构,确保分解后的内容与之前一样。无论是否遗留,代码就是代码,您可以修改它。

  • 如果由于某种原因你太害怕、不熟练或懒得重构并且幸运的是怪物类实际上不需要任何方面的建议,你可以修改你的切入点,使其不那么全局和更具体,不包括怪物类甚至可能是遗留包的更大部分,具体取决于您的用例。


推荐阅读