- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
MethodHandles.Lookup.defineClass
在运行时从字节数组生成一个新类。
返回类在什么情况下可以被垃圾回收?它是否在与 Lookup
对象关联的类加载器的生命周期内保留,或者如果不再引用 Class
对象,它是否可以被垃圾收集?
最佳答案
通过 MethodHandles.Lookup.defineClass
创建的类像任何其他类一样在定义类加载器中注册,并且可以像普通类一样通过名称引用,这与 defineHiddenClass(...)
不同。与 JDK 15 一起引入(请参阅答案末尾)。在这些类被解析之前注册时,它们甚至可能会取代静态编译的类,如下例所示:
import java.lang.invoke.MethodHandles;
import java.nio.charset.StandardCharsets;
public class LookupDynamicClass {
public static void main(String[] args) throws IllegalAccessException {
MethodHandles.Lookup lookup = MethodHandles.lookup();
lookup.defineClass(("Êþº¾\0\0\0005\0\26\11\0\11\0\12\10\0\13\12\0\14\0"
+"\15\7\0\16\7\0\17\1\0\3foo\1\0\3()V\1\0\4Code\7\0\20\14\0\21\0\22\1\0"
+"\30hello from dynamic class\7\0\23\14\0\24\0\25\1\0\4Lazy\1\0\20java/"
+"lang/Object\1\0\20java/lang/System\1\0\3out\1\0\25Ljava/io/PrintStream;"
+"\1\0\23java/io/PrintStream\1\0\7println\1\0\25(Ljava/lang/String;)V\6\0"
+"\0\4\0\5\0\0\0\0\0\1\0\11\0\6\0\7\0\1\0\10\0\0\0\25\0\2\0\0\0\0\0\11²\0"
+ "\1\22\2¶\0\3±\0\0\0\0\0\0").getBytes(StandardCharsets.ISO_8859_1));
Lazy.foo();
}
}
interface Lazy {
static void foo() {
}
}
此示例动态定义了一个 Lazy
类,其 foo()
方法在被调用时将打印 hello from dynamic class
。
在像 HotSpot 这样的 JVM 上,符号引用“Lazy
”被延迟解析,即在尝试调用 Lazy.foo()
时,这将最终进入动态定义的类。对于热切解析符号引用的 JVM,Lazy
类在调用 MethodHandles.Lookup.defineClass
时已经存在,因此,一个带有消息的 LinkageError
像“尝试重复定义懒惰”将被抛出。
换句话说,这些动态生成的类与静态编译的类共享相同的 namespace (类加载上下文)。像普通类一样在类加载器中注册,它们只能在定义类加载器变得不可访问(包括其所有定义的类)时被垃圾收集,就像普通类一样。
引入了 JDK 15 defineHiddenClass(...)
它可用于定义未在类加载器中注册的类,并且还能够访问查找类的 private
成员,类似于较旧的非标准功能 sun.misc.Unsafe.defineAnonymousClass
。
该行为由 ClassOption
控制参数。
NESTMATE
允许访问查找类的 private
成员及其嵌套成员(通常是内部类)
STRONG
防止类被卸载,直到类加载器变得不可访问,虽然我不知道为什么有人会想要这个。如果没有此选项,隐藏类可以在不存在对它的引用时立即进行垃圾收集和卸载。
这是该示例的改编版本:
public class LookupHiddenClass {
public static void main(String[] args) throws Throwable {
var lookup = MethodHandles.lookup();
lookup = lookup.defineHiddenClass(("Êþº¾\0\0\0005\0\26\11\0\11\0\12\10\0\13\12"
+"\0\14\0\15\7\0\16\7\0\17\1\0\3foo\1\0\3()V\1\0\4Code\7\0\20\14\0\21\0\22\1\0"
+"\27hello from hidden class\7\0\23\14\0\24\0\25\1\0\4Lazy\1\0\20java/"
+"lang/Object\1\0\20java/lang/System\1\0\3out\1\0\25Ljava/io/PrintStream;"
+"\1\0\23java/io/PrintStream\1\0\7println\1\0\25(Ljava/lang/String;)V\6\0"
+"\0\4\0\5\0\0\0\0\0\1\0\11\0\6\0\7\0\1\0\10\0\0\0\25\0\2\0\0\0\0\0\11²\0"
+ "\1\22\2¶\0\3±\0\0\0\0\0\0").getBytes(StandardCharsets.ISO_8859_1), true);
lookup.findStatic(lookup.lookupClass(), "foo", MethodType.methodType(void.class))
.invokeExact();
var q = new ReferenceQueue<Class<?>>();
var r = new PhantomReference<>(lookup.lookupClass(), q);
lookup = null;
do System.gc(); while(q.remove(1000) != r);
System.out.println("class collected");
}
}
虽然不能保证 System.gc()
将执行实际的垃圾收集,也不能保证它确实收集特定对象,但使用 OpenJDK 的默认配置它可以重复打印
hello from hidden class
class collected
关于java - MethodHandles.lookup().defineClass保留,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52710966/
我正在为我的自定义编程语言开发 REPL。它在编译器之上实现,用于为输入生成字节码并将其转换为 Class。使用 sun.misc.Unsafe.defineClass(String, byte[],
我正在使用 JVMTI 编写一个应用程序。我正在尝试检测字节码:通过在每个方法条目上注入(inject)方法调用。 我知道该怎么做,但问题出在仪器类中,假设它被称为 Proxy ,我使用 JNI 函数
我使用 ClassLoader 中的方法 defineClass() 从字节数组中定义一个类。我使用反射获取此方法: ClassLoader.class.getDeclaredMethod(
我正在使用自定义类加载器加载类。在大多数情况下,一切正常,但有时当我加载特别复杂的项目/库时,我会遇到一个奇怪的错误: Exception in thread "main" java.lang.Cla
我有一个类文件,我正在通过对 ClassLoader.defineClass 的反射调用从中读取字节并将其定义为 Class 对象。 我收到的 NoClassDefFoundError 消息是: Ca
我正在使用 jdk-10.0.2 和 gradle 4.7,在构建我的项目时出现此错误。 Unable to find method 'sun.misc.Unsafe.defineClass(
意图: 我正在使用 java.lang.instrument包来为 Java 程序创建一些工具。我的想法是,我通过这个系统使用字节码操作,以便在每个方法的开头和结尾添加方法调用。一般来说,修改后的 J
我正在尝试将带有 EJB 1.1 内容的旧代码库部署到 Weblogic 10.3.6 并不断收到这个奇怪的错误 Class bytes found but defineClass()failed f
我正在尝试使用反射从 ClassLoader 获取 defineClass 方法 ClassLoader cl = this.getClass().getClassLoader(); Method m
我正在使用以下方法从 jar 条目(仅包含类文件)中读取字节。 jar里面没有jar文件。 private List readFromJarFile(File cp) { List cbyte
我使用 ASM 生成了一个类,现在我尝试使用 ContextClassLoader 加载该类: (.defineClass classloader (str pkg "." classname) co
我正在使用 JNI 调用 DefineClass() 从 C 定义一个 java 类,然后我为类中的 native 方法注册 native 回调。该类有两个静态方法,都是 native 方法。我使用
我正在开发一个应用程序,我在自定义启动器中按以下方式直接将一些类注入(inject) JVM: 第 1 步:使用 LoadLibrary(C++ 代码)加载 jvm dll 第 2 步:实际注入(in
我尝试扩展类加载器。我的 ClassLoader.loadClass 是: protected synchronized Class loadClass(String name, boolean r
我已经使用 java 16 启动了一个项目,但我在项目中到处都遇到错误: An error has occurred. See error log for more details. Unable t
我正在尝试在 Appcelerator Hyperloop 中做最简单的事情来定义/创建我自己的类,但这导致我的构建失败(无法为模拟器或设备构建)并出现构建时错误控制台。 我刚刚开始一个新的空白 Al
我正在尝试使用 Spring MongoTemplate 将一些数据(对象列表)插入到 mongoDB 中,但出现异常: 14:08:04.430 [main] DEBUG org.springfra
我是一名优秀的程序员,十分优秀!