问题标签 [escape-analysis]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
3 回答
1004 浏览

java - JVM中的确定性垃圾收集

我想知道是否存在热点 JVM 或任何其他 JVM 可以确定性地进行垃圾收集的任何实例。我知道逃逸分析,但想知道它是否也适用于堆分配的对象。我的意思是在这样的 C++ 代码中,可以从堆中进行确定性垃圾收集

当然在Java中类似

在垃圾收集关闭数组时应该是确定性的。看起来,逃逸分析似乎专注于在堆栈上分配关闭数组的可能性,但即使在堆上分配,在这种情况下,我不明白为什么在离开 ma()' 时无法收集它范围

0 投票
1 回答
147 浏览

java - Java 手动堆栈分配

所以我对 Java 比较陌生,只是阅读了这篇关于逃逸分析的非常有趣的 Wikipedia 文章。但是,它提到使用堆栈分配的唯一一次是当对象没有逃避方法调用时。这似乎有些有限;但话又说回来,我想不出任何其他时间我想要一个分配给堆栈的对象。所以我想知道:

1) 是否有任何其他时间将对象分配到堆栈是有意义的?
2)有没有办法手动将对象分配给堆栈,而不是堆?
2.5)如果有,这样做会更快吗(对于不逃避该方法的对象),而不是必须通过逃避分析来解决这个问题?或者有什么方法可以告诉 Java 类似“在这种方法中,我需要每个对象都在堆上,不要费心去查看是否有任何对象可以在堆栈上”?

谢谢!

0 投票
1 回答
101 浏览

java - JVM 可以省略短期对象的创建,这样我就可以在不影响性能的情况下进行重构吗?

有时在算法的过程中,我们需要计算或简单地存储几个相互依赖或彼此分开没有任何意义的值。

就像一个(非常荒谬,但重要的是,简单)示例让我们在 anint[]中找到最接近 number的两个不同值3

我们不能只在同一个类中创建方法computeA()computeB()因为计算ab是相互依赖的。所以计算a并且b只是要求重构为一个单独的类:

因此更高级别的代码变得清晰明了:

但是(如果我错了,请纠正我)它引入了,至少对于某些级别的优化,一个实例化,然后是一个新对象的垃圾收集(只是来自伊甸园,但无论如何)只是为了清楚你的代码。并且在堆栈中寻找 int 也会变成在堆中寻找对象。

这里的问题是: JVM 是否足够聪明,最终可以优化重构的代码以像未重构的代码一样运行?

我想将几个变量组合成一个新对象只是为了更清晰的代码的另一种情况是,当我想a()通过引入一个新类来将一个长方法重构为几个新方法时,该类C包含特定于a()'s 调用的数据,因此包含那些对这些数据进行操作的几种新方法。我在实现一个表示一组链的类时偶然发现了这种情况,我们可以向其中添加新的链接(节点对),从而扩展现有的链,将两条链组合在一起,或者创建一个包含两个节点的新链。让我们仅出于某种观点讨论该特定类:

要正确拆分addLink为 的几个方法SetOfChains,这些新方法中的每一个都必须有很多参数,因为addLink()addLink(). 将该数据保存到的专用字段SetOfChains也是可能的,但有异味且难以表达(因为它仅在方法调用期间才有意义),因此显然我创建了一个新的内部类来将该数据保存在其字段中并执行所有算法步骤,chains像未重构的那样改变外部字段addLink()

但是由于在功能上这相当于让我的旧 long unrefactored addLink(),JVM 是否可以使生成的指令与未重构情况下一样优化,就好像没有任何LinkAddition对象一样?

因此,要在这堵文字墙下画出底线:如果我通过将数据和方法提取到新而不是方法来争取易于理解的代码,是否必然会导致性能下降?

我是否正确理解所描述的案例正是逃逸分析的内容?

0 投票
1 回答
1531 浏览

performance - 在 Go 中导致不必要的堆分配的可变参数函数

我目前正在研究 Go 中的一些性能敏感代码。在某一时刻,我有一个特别紧密的内循环,它连续做三件事:

  1. 获得几个指向数据的指针。如果发生罕见错误,这些指针中的一个或多个可能是nil.

  2. 检查是否发生此错误,如果发生则记录错误。

  3. 使用存储在指针中的数据。

下面显示的是一个具有相同结构的玩具程序(尽管指针实际上永远不会为 nil)。

当我在我的机器上运行它时,我得到以下信息:

但是,如果我删除打印语句,我会得到以下信息:

由于实际上从未调用过 print 语句,因此我调查了 print 语句是否以某种方式导致指针分配到堆而不是堆栈上。-m在原始程序上运行带有标志的编译器会给出:

在打印无语句程序上执行此操作时

确认即使是未使用fmt.Printf()的也会导致堆分配,这对性能有非常实际的影响。我可以通过替换fmt.Printf()为不执行任何操作并将*ints 作为参数而不是interface{}s 的可变参数函数来获得相同的行为:

我认为这种行为是因为 Go 会在将指针放在切片中时在堆上分配指针(尽管我不确定这是转义分析例程的实际行为,但我不知道它如何能够安全地否则做)。

这个问题有两个目的:首先,我想知道我对情况的分析是否正确,因为我不太了解 Go 的逃生分析是如何工作的。其次,我想要在不引起不必要分配的情况下保持原始程序的行为的建议。我最好的猜测是Copy()在将指针传递到 print 语句之前将函数包装在指针周围:

其中Copy()定义为

虽然这给了我与无打印语句情况相同的性能,但它很奇怪,而不是我想为每个变量类型重写然后环绕我所有的错误日志代码的那种东西。

0 投票
1 回答
211 浏览

java - 逃脱分析疑点

我想我会做一个逃逸分析的小实验(Java 8、64 位服务器 JVM)。我想出了这个非常愚蠢的“应用程序”,我在其中创建了很多 Address 对象(它们由邮政编码、街道、国家和生成对象的时间戳组成。此外,Address 有一个 isOk() 方法,它返回如果时间戳可以被 7 整除,则为 true...)。

所以这是程序:

到目前为止一切顺利,我使用 jVisualVM 对其进行了分析,在它运行时堆上没有 Address 对象。整个应用程序在几秒钟内完成。

但是,当我像这样重构它时:

Baaang,没有逃逸分析,每个 Address 对象最终都分配在堆上,垃圾回收周期很长。为什么会这样?我的意思是,Address 实例不会以任何一种方式转义(在第二个版本中,Address 对象的范围更窄,它们不会转义方法,甚至不会转义 for 循环块),那么为什么两个版本的行为如此不同呢?

0 投票
1 回答
309 浏览

java - Does java escape analysis also work for arrays with only one element?

Background:

When you extract methods out of long code pieces, you often run into the call-by-value problem with primitive variables. You cannot change those primitive parameters in the extracted method so that the caller sees the changes. You can avoid that by making the primitive variable an array with only one element. Then it is effectively used call-by-reference. However it is now an object on the heap. Is the escape analysis of Java clever enough to understand that and use the stack despite that?

Given following code and the case it could not be inlined:

0 投票
1 回答
1755 浏览

javascript - 逃逸分析

在许多语言中,局部变量位于调用堆栈中

在 JavaScript/Python 中,只有闭包变量位于堆中,因为它们必须存在于函数调用之外,它们是被创建的。


在 GO 中,一些 GO 类型(如 slice 类型[]int)确实引用了内存的其他部分,如 JavaScript/Python。

在 GO 中,并非所有类型的变量都包含引用,例如 Javascript/Python。

例如,

1)[3]int类型变量b直接存储 's 的数组int,如 C,除了 C 允许使用 C 语法访问每个数组元素位置&b[index],以获得更多控制

2)int类型变量c直接存储一个int值,就像 C 一样,不同的是,C 通过提供 syntax( &c) 来获得更多的控制权来获得位置访问。


在 GO 中,我的理解是,对于堆/堆栈上的局部变量,取决于在示例代码(如下)中应用编译器的转义分析,

这告诉编译器变量a超出其范围,因此在堆中分配,而不是在堆栈中分配。


问题:

变量是否a在堆中分配?

0 投票
1 回答
366 浏览

go - 关于堆栈分配,什么被认为是 Go 中的“小”对象?

编码:

然后运行go build -gcflags='-m' . 2>&1以检查内存分配详细信息。结果:

我的问题是为什么a是小物体和b大物体?

make64KB 将逃逸到堆中,而更少的将分配到堆栈中。请问_MaxSmallSize = 32 << 10是什么原因?

go env

0 投票
1 回答
344 浏览

java - Hotspot JVM 是否在 On Stack Replacement 编译期间执行 Escape 分析?

考虑以下代码:

foo当 C2 OSR 编译开始时,Hotspot JVM 是否能够在堆栈上进行标量化?我想这可能是有问题的,因为堆中已经存在一个活动对象,因此可能无法将对象从堆“移动”到堆栈和寄存器。

0 投票
1 回答
108 浏览

java - 逃逸分析是否正确处理 Thread.holdsLock()?

当我使用以下命令运行此示例时,它可以正常工作(打印为真)-XX:+DoEscapeAnalysis -server

另一方面,简短且不太详细的Java HotSpot™ 虚拟机性能增强文档说明如下:

服务器编译器还消除了所有非全局转义对象的锁定。

因此,如果逃逸分析消除了这里不必要的同步,它应该打印false.

我猜逃逸分析处理holdsLock得当(消除锁不坏holdsLock()),但我想看看一些官方参考或相关的 JVM 源代码片段。