I was touching Graal and didn't know what the partial escape analysis was, so I looked it up.
↓ Articles written about Graal / GraalVM https://qiita.com/kinshotomoya/items/39a821dd6a6a52202c0a
The sample code is written in scala.
The object reference exists outside the method or in a different thread. When escaped, you can refer to an object from an unspecified number of places.
When can we say that an object is escaped in the actual code? There are mainly the following three conditions.
A reference to a, which is an instance of Object, can be referenced beyond the hoge method. Can also be referenced from the foo method
case class Object()
object Test {
def hoge: Object = {
val a = Object()
foo(a)
}
def foo(obj: Object) = ???
}
References to instance b of an Object can be referenced beyond the hoge method. The b2 variable has a reference to object a.
case class Object()
object Test {
def hoge: Object = {
val b = Object()
b
}
val b2 = hoge()
}
In other words, it is possible to refer to the above example instances a and b beyond the method.
Parse whether the instance reference escapes outside the method or to another thread. There are various algorithms.
If the escape analysis shows that the reference is closed inside the method,
If the instance is used only within the method, it is effective to store it in the stack area that is released after the method ends.
References from only a single thread eliminate the need for synchronization between threads.
As a result of escape analysis, the compiler optimizes the code. An example is shown.
I have the following code.
class Person {
def get(name: String) = {
val person: Person = Person(name)
if (person.name === "hoge") {
}
...
}
}
case class Person(name: String)
An instance of the Person object, person, is not escaped. In such cases, the compiler inlines and optimizes.
class Person {
def get(name: String) = {
// val person: Person = Person(name)
if (name === "hoge") { //Inline
}
...
}
}
case class Person(name: String)
This is one of the features of the new JIT compiler Graal. It can be partially optimized.
If you have the following code.
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)
If cachePerson exists, the object person will not be escaped. The compiler parses that and modifies it into the following code.
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)
You can move val person: Person = Person (name)
under ʻelse and, if
cachePerson` exists, eliminate the memory allocation to the heap area. Instead, it is stored in the stack area, improving processing efficiency.
If cachePerson
does not exist, person is escaped and stored in the heap area.
Recommended Posts