lambda 表达式的 Java 堆转储分析

Posted

技术标签:

【中文标题】lambda 表达式的 Java 堆转储分析【英文标题】:Java heap dump analysis for lambda expressions 【发布时间】:2015-06-19 09:42:01 【问题描述】:

我的 Java 应用程序堆转储显示我的类中使用的特定 lambda 已锁定一些内存,并且在 GC 期间没有被释放。

Heap 将特定的匿名 lambda 类显示为 ParentClass$$Lambda$ID,在当前情况下,ID 为 79(附图片)。这个 ID 似乎与类中存在的 lambda 的数量没有任何关系,因此我们无法得出代表哪个 lambda 的结论。我有兴趣指出确切的 lambda 表达式,因为它有助于分析、修复和测试相关场景。

使用 DJ 反编译类文件并没有帮助,因为它将 lambda 表达式重新创建为可读的代码。如果对此有任何想法,请告诉我。

【问题讨论】:

如果 lambda 表达式分配了大量内存,则其中必须有捕获的值。因此,检查实例可能会引导您了解信息,即它是哪个实际的 lambda 表达式。此外,您可以分析 allocations 以找到源... @Holger 我需要在这里更精确。这个类有多个 lambdas 意味着类似类型的不同目的。我将用简单的术语进行描述——比如我有 getAccountName、getAccountBalance、getAccountNominee 等方法——假设这些方法中的每一个都会调用不同服务器上的 Web 服务,并且响应将返回给其他方法进行处理而不保留状态。这里的问题是其中一项服务正在花费无限时间,并且服务和我的应用程序都没有超时,这将“DefaultHttpClient”(行)保持为活动对象。所以没有办法确定哪个 lambda。 除了以传出引用的形式查看其属性(捕获的值和参数)之外,您还可以查看传入引用,即持有 lambda 的东西。通常应该足以找到它 如果您的分析器有分配记录,您也可以使用它,这应该会为您提供带有已分配 lambda 的行号的呼叫站点。 @Pavan Kumar:这是一种奇怪的方法,因为 JVisualVM 可以直接收集堆转储。它的分析器还能够跟踪分配站点。当您没有真正使用您拥有的工具时,不要要求其他工具。 【参考方案1】:

尝试定义系统属性

jdk.internal.lambda.dumpProxyClasses=/path/to/dir

在调用 JVM 时。这将导致运行时将动态生成的 lambda 类写入磁盘,您可以在其中使用javap 检查它们。这将使您能够查看它们包含哪些字段(捕获的变量),以及 lambda 对应的 lambda body 方法。

【讨论】:

除了bugs.openjdk.java.net/browse/JDK-8023524 之外,没有太多可用的文档 - 尽管可能不是跨 JDK 的解决方案。我会试一试,让你知道。 很好的解决方案,希望通用的东西(不是特定于 jvm)以类似的方式存在。 @Pavan Kumar:由于这些类的全部存在是特定于 JVM 的,因此无法选择转储它们不是特定于 JVM... 我似乎无法弄清楚如何运行 javap。它不想在我给它的课程上运行。说。错误:找不到类:

以上是关于lambda 表达式的 Java 堆转储分析的主要内容,如果未能解决你的问题,请参考以下文章

Java技术专题「原理分析系列」Lambda表达式实现原理分析

Java Lambda表达式 实现原理分析

用于分析大型 Java 堆转储的工具

分析大型 Java 堆转储 - 内存错误

Java JVM 动态方法调用指令 invokedynamic 实现分析(以 Lambda 表达式实现原理为例)...

深入理解Java虚拟机——虚拟机堆转储快照分析工具(jhat)