Java的转义解析是什么意思?

引言

在使用Graal时,我遇到了部分转义解析的问题,完全不知道该怎么处理,于是做了一些调查记录下来的笔记。

以下是一篇关于Graal・GraalVM的文章。
https://qiita.com/kinshotomoya/items/39a821dd6a6a52202c0a

示例代码使用scala编写。

逃逸是指

当对象的引用存在于方法之外或不同的线程时。
如果进行逃逸,就可以从多个不特定的地方引用到对象。

逃逸的条件

在实际的代码中,我们如何确定对象何时被逃逸?
主要有以下三个条件。

    1. 在方法的参数中指定

 

    通过return语句返回(指定返回值)

1. 在方法的参数中指定

对于作为Object实例的a的引用,可以在hoge方法之外引用。
也可以在foo方法中引用。

case class Object()

object Test {
  def hoge: Object = {
    val a = Object()
    foo(a)
  }

  def foo(obj: Object) = ???
}

2. 使用return返回(指定为返回值)

对象b对实例的引用可以通过hoge方法来引用。
变量b2持有对对象a的引用。

case class Object()

object Test {
  def hoge: Object = {
    val b = Object()
    b
  }

  val b2 = hoge()
}

换句话说,上述例子中的实例a和b可以在方法之外进行引用。

转义解析是什么?

分析实例引用是否逸出到方法外或其他线程中。有各种算法。

如果没有经过转义会被解析成什么?

透過進行转义分析后,发现引用已被封闭在方法内部。

1. 将实例存储在栈中而不是堆中。

如果只在方法内部使用实例,将其存储在方法结束后会被释放的堆栈空间中会更有效。

2. 在执行方法时,忽略不必要的同步。

如果只从单个线程进行引用,则不需要线程间同步。

最优化案例

逃逸分析的结果,编译器会对代码进行优化。这是一个例子。

将其内联化

有如下代码。


class Person {
  def get(name: String) = {
    val person: Person = Person(name)
    if (person.name === "hoge") {
    }
    ...
  }
}

case class Person(name: String)

对于作为Person对象的实例的person未被转义。
在这种情况下,编译器会进行内联和优化。

class Person {
  def get(name: String) = {
    // val person: Person = Person(name)
    if (name === "hoge") { // インライン化

    }
    ...
  }
}

case class Person(name: String)


某些逃逸分析

Graal是新一代的JIT编译器,其特点之一是可以进行部分优化。

如果有以下的代码。

class Person {
  def get(name: String) = {
    val person: Person = Person(name)
    val cachePerson = Cache.get(name)
    if (cachePerson.isDefined) {
      cachePerson
    } else {
     addToCache(person)
     person
    }
  }
}

case class Person(name: String)

如果存在cachePerson,则对象person不会被逃逸。
编译器会分析此情况并将其转换为以下代码。


class Person {
  def get(name: String) = {
    val cachePerson = Cache.get(name)
    if (cachePerson.isDefined) {
      cachePerson
    } else {
     val person: Person = Person(name)
     addToCache(person)
      person
    }
  }
}

case class Person(name: String)

如果存在cachePerson, 可以将person: Person = Person(name)移动到else语句中,这样就可以省去在堆内存中分配内存的操作。相反,它会被存储在栈内存中,从而提高了处理效率。

如果cachePerson不存在,person会被逃逸并存储在堆区域。

请参考

    • https://www.slideshare.net/jyukutyo/graal-in-graalvm-a-new-jit-compiler

 

    • https://docs.oracle.com/javase/jp/11/vm/java-hotspot-virtual-machine-performance-enhancements.html#GUID-6BD8FCB5-995B-4AE9-BFAA-B2C7DE2BA5CD

 

    • https://www.weblio.jp/wkpja/content/%E3%82%A8%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%97%E8%A7%A3%E6%9E%90_%E3%82%A8%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%97%E8%A7%A3%E6%9E%90%E3%81%AE%E6%A6%82%E8%A6%81

 

    https://gist.github.com/kawasima/32b8097163029d452553e4ae5b8e070b
广告
将在 10 秒后关闭
bannerAds