2

.Net 中,您似乎不能

  1. 动态编译代码
  2. 直接调用已编译的代码(即没有“远程处理”、编组等)
  3. (仅)从内存中删除已编译的代码

您必须在 2.(通过将代码生成到调用 AppDomain 本身)或 3.(通过将代码生成到一次性 AppDomain)之间做出决定,但您不能同时拥有两者。

现在我很好奇这在Java中是否可行。我对 ClassLoaders 知之甚少,但似乎在 Java 中我可以

  1. 将代码动态编译成一次性类加载器
  2. 直接调用已编译的代码(例如,通过对预定义接口的虚拟方法调用),无需任何封送处理
  3. 删除对已编译类和一次性类加载器的所有引用,以便 GC 负责删除

这个假设有效吗?

4

1 回答 1

2

是的,您可以在代码之外的类加载器中编译/加载一个类,调用它没有问题。

是的,动态代码将达到“全部性能”。没有区别。但是,新加载的代码将以解释模式启动,并且在编译之前需要预热。

但是,第 3 点非常棘手。

  • “泄漏”丢弃的类加载器非常容易/可能。类加载器保留对其加载的类的引用。每个类都包含对其类加载器的引用。每个对象都是对其类的引用。因此,只要你有一个对象或类的引用,该对象或类是用丢弃类加载器加载的,它和它加载的类就保持活动状态。因为很容易引用一个对象,所以“类加载器”泄漏很常见。
  • 这取决于 GC 配置和 JVM 版本,它实际上是 GC 传递加载的类。您可能需要额外的标志来启用它。就像 CMS GC '-XX:+CMSClassUnloadingEnabled'。
  • 有一个代码缓存(在 OpenJDK/Hotspot 中),用于保存已编译的代码。如果您在应用程序的整个生命周期中一直加载代码,则可能会超出此缓存。在较旧的 JVM 中,它刚刚填满,一旦填满,它就会停止编译代码,从而降低性能,除非您启用刷新该缓存 (-XX:+UseCodeCacheFlushing)。Afaik 在较新的版本中默认刷新。仔细检查一下。您可能需要密切关注代码缓存。(例如通过 JMX)
于 2016-05-04T07:14:38.453 回答