- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我们通常知道一个类cannot be unloaded来自 ClassLoader,但 lambda 的合成类似乎可以。
证明:
public class Play {
static String test = new String("test");
public static void main(String[] args) throws Exception {
WeakReference<String> wr = new WeakReference<>(test);
Runnable run = test::toString;
System.out.println(Play.class.getClassLoader() == run.getClass().getClassLoader());
System.out.printf("sys=%s, lambda=%s", Runnable.class, run.getClass());
run.run();
test = null;
run = null;
while (wr.get() != null) {
System.gc();
}
}
}
输出:
true
sys=interface java.lang.Runnable, lambda=class Play$$Lambda$1/918221580
<then terminates>
这表明 lambda 的闭包引用的字符串(将被合成类引用)被取消引用,这意味着合成类也必须被 GC 处理。这是有道理的,否则会出现各种基于类加载器的内存泄漏。
我的问题是他们是否打破了无法卸载类的设计来做到这一点?如果是这样,我们可以用我们自己的类来做到这一点吗?
最佳答案
有趣的是,尽管您的测试不足以确定这一点,但实际上,为 lambda 表达式生成的类可以被垃圾收集,如下面的代码可以证明:
import java.lang.invoke.*;
import java.lang.ref.WeakReference;
public class LambdaClassUnloading {
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup l = MethodHandles.lookup();
MethodType t=MethodType.methodType(void.class);
Runnable r=(Runnable)LambdaMetafactory.metafactory(l, "run",
MethodType.methodType(Runnable.class), t,
l.findStatic(LambdaClassUnloading.class, "testMethod", t), t)
.getTarget().invokeExact();
System.out.println("generated "+r);
r.run();
WeakReference<Class<?>> ref=new WeakReference<>(r.getClass());
r=null;
while(ref.get()!=null) System.gc();
System.out.println("class collected");
}
private static void testMethod() {
System.out.println("testMethod() called");
}
}
这会打印类似的东西:
generated java8test.LambdaClassUnloading$$Lambda$1/723074861@77459877
testMethod() called
class collected
虽然数字可能会有所不同。
但出于实际目的,重要的是要了解上面代码反射调用的生成器设施通常是通过 invokedynamic
字节码指令触发的,该指令将永久链接到首先完成引导过程。
换句话说,考虑到当前 JRE 的处理方式,只要包含 invokedynamic
指令的代码是可访问的,永久链接的 lambda 类也会持续存在。这与 Andremoniy’s answer 中演示的行为相匹配; Runnable run = test::toString;
行的代码可以再次执行并将生成与第一次执行相同的类的实例,因为它的构造函数已永久链接到它。
但理论上,替代的 JRE 实现可以让 Bootstrap 方法返回一个 MutableCallSite
并在以后重新定位它,例如生成更优化类的实例或强制在语义等价的 lambda 表达式之间共享类。在那种情况下,当没有更多的 lambda 实例时,现有的 lambda 类可以比它们的定义类更早地被垃圾回收。
所以答案是,确实有一个“神奇的类卸载”,但目前,它与大多数实际用途无关,当然,如果它发生在未来的 JVM 中,它仍然会保留由Java 语言规范。无论您的方法引用 test::toString
捕获的实例如何存储,如果函数接口(interface)的实例 无法访问,它都不会阻碍其收集。
如果您对更多细节感兴趣,文章“anonymous classes in the VM” by John Rose提供介绍。您还可以搜索 sun.misc.Unsafe.defineAnonymousClass
...
关于java - 合成 lambda 类的神奇类卸载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34927171/
1.使用start-all.sh启动hadoop服务时,提示输入 您确定要继续连接吗(是/否) 当我通过脚本启动它时如何抑制这个提示,现在我正在使用期望模块,但我认为可能有一种更简单的方法来做到这一点
我安装了在 Ubuntu 12.04 下运行的 Geonode R 2.01。我尝试使用以下命令卸载它: sudo apt-get remove --purge geonode sudo apt-ge
假设我有 AppDomainA,它启动 AppDomainB。 AppDomainB 然后启动 AppDomainC。 如果在 AppDomainA 中卸载 AppDomainB,AppDomainC
关闭。这个问题是off-topic .它目前不接受答案。 想改善这个问题吗? Update the question所以它是 on-topic对于堆栈溢出。 8年前关闭。 Improve this q
我尝试使用以下命令从我的 Ubuntu 中卸载 NGinX: sudo apt-get remove nginx-core nginx-full nginx-light nginx-extras n
我已经从 /Applications/ 中删除了 MacVim目录,但当我输入 vim 时在终端中显示错误:no such file or directory: /Applications/MacVi
我的页面中有一个 iframe,该 iframe 嵌入了一个不在我的服务器上的网站。 我正在寻找一种在 iframe 重定向之前触发函数的方法。例如,当用户单击 iframe 内的链接并且 ifram
看来我被 Visual Studio 的 Atomineer Pro 文档加载项挟持了!试用期结束了,我没有用了!但现在每次我在 Visual Studio 中做某事时,我都会收到一条错误消息并发送到
我有一个使用 WiX 完成的安装程序。安装完成后,它会启动一个应用程序,在 Explorer 进程中注入(inject)一些代码。 目前,当我卸载时,重新启动管理器会启动并关闭我的应用程序和资源管理器
在我的网络应用中,我需要在用户离开页面之前发送他们更改的最新数据。 我在页面卸载时调用这样的函数: window.onbeforeunload=sendData; 这就是函数内部调用的内容 funct
我使用 jQuery 和 history.js 来管理部分页面之间的动态转换;这样我就可以避免重新加载整个文档。其中一些部分页面调用自己独特的 javascript 文件。虽然页面之间的转换运行良好,
我需要处理应用程序包的变化,我这样写我的 mainfest mainfest.xml 我的接收器类
我目前在使用大量内存方面遇到了麻烦,我正在尽一切努力削减和优化涉及内存的代码...目前我的游戏的大部分 Nib 文件都加载了所有它在 ViewDidLoad 中的变量,现在我的问题是,在我的 view
如何从系统中删除 composer Php Dependecny Manager? 它说卸载无法继续,因为以下应用程序正在使用需要删除的文件。 Windows 资源管理器 最佳答案 我遇到了同样的问题
所以我使用 stow 在服务器上安装了 Python 2.7.1 源代码 .我过去很粗心,在处理源代码安装时我试图保持井井有条。所以,输入 stow。现在我使用 wget 安装了 easy_insta
有谁知道如何卸载 MacRuby?我在使用 RubyCocoa 然后决定试用 MacRuby,在安装 MacRuby 之后,RubyCocoa 已经停止工作。所以我想删除 MacRuby,但我找不到任
我无法从 64 位 EC2 卸载 mongo。在/usr/bin 我有 mongo 和 mongod 等等。当我从任何地方键入 mongo 时,它会在 1.8 版打开 shell。我现在下载了 2.0
本文实例讲述了Android编程实现监控apk安装,卸载,替换的方法。分享给大家供大家参考,具体如下: ?
1说明 mysql++是mysql开发团队为OO编程提供的C++开发库,是对mysql提供的底层数据存取API进行的C++封装,用其手册上的说法是:复杂而又庞大,当然功能也更强大。 Mysql+
自从我开始建立我的网站那天起,我安装了很多包,有时是为了测试一堆代码,有时是为了项目本身(后来我发现这不是需要的包)。但是现在,当我运行 pip freeze 时,我有一个包列表,我很难卸载不使用的包
我是一名优秀的程序员,十分优秀!