- Mastering High Performance with Kotlin
- Igor Kucherenko
- 732字
- 2021-06-25 20:55:22
String pool
The String pool is a set of String objects stored in the Permanent Generation section of the heap. Under the hood, an instance of the String class is an array of chars. Each char allocates two bytes. The String class also has a cached hash that allocates four bytes, and each object has housekeeping information that allocates about eight bytes. And if we're talking about Java Development Kit 7 (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/java/lang/String.java?av=f) or lower, the String class also has offset and length fields. Since String is the most used type, the instances of the String class allocate a significant part of the heap.
To reduce the load on memory, the JVM has the String pool as the implementation of the Flyweight Design Pattern because memory space can be crucial for low-memory devices such as mobile devices.
Whenever double quotes are used to create a new instance of the String class, the JVM first looks for an existing instance with the same value in the String pool. If an existing instance is found, a reference to it is returned. Otherwise, a new instance is created in the String pool and then the reference to it is returned. When we use a constructor, we force the creation of a new instance of the String class in the heap:

This technique is called copy-on-write (COW). The point is that when a copy of the object is requested, the reference to the existing object is returned instead of creating a new one. In code, it may look like this:
fun main(vars: Array<String>) {
val cat1 = "Cat"
val cat2 = "Cat"
val cat3 = String("Cat".toCharArray())
println(cat1 === cat2)
println(cat1 === cat3)
}
The output:
true
false
Kotlin has its own kotlin.String class. It's not the same as the java.lang.String class. And kotlin.String doesn't have a constructor that takes another instance of the String class.
With the COW, when trying to modify an object through a particular reference, a real copy is created, the change is applied to it, and then the reference to the newly created object is returned. The following diagram illustrates this:

In code, it may look like this:
fun main(vars: Array<String>) {
val cat1 = "Cat"
val cat2 = cat1.plus("Dog")
println(cat1)
println(cat2)
println(cat1 === cat2)
}
And here's the output:
Cat
CatDog
false
This technique is good for creating simple and reliable code and can be very useful in a concurrent application, as you can be sure that your object won't be corrupted with another thread.
Let's look at the following example:
class User(val id: Int = 0, val firstName: String = "", val lastName: String = "")
fun main(vars: Array<String>) {
val user = User()
val building = "304a"
val query = "SELECT id, firstName, lastName FROM Building " + building + " WHERE firstName = " + user.firstName
}
Each concatenation creates a new instance of String. So many unnecessary objects are created in this code. Instead of concatenation, we should use StringBuilder or String Templates (https://kotlinlang.org/docs/reference/basic-types.html#string-templates), which uses StringBuilder under the hood but is much simpler to use:
val query = "SELECT id, firstName, lastName FROM Building $building WHERE firstName = ${user.firstName}"
But how can we put a String object into the String pool if we receive it from the outside? Here is how:
val firstLine: String
get() = File("input.txt")
.inputStream()
.bufferedReader()
.use { it.readLine() }
fun main(vars: Array<String>) {
println(firstLine === firstLine)
}
This is the output:
false
To put the value of the firstLine variable in the String pool, we have to use the intern() method. When this method is invoked, if the pool already contains a string equal to the value of the object, then the reference to the String from the pool is returned. Otherwise, this object is added to the pool and a reference to this object is returned. The intern() method is an implementation of interning. It's a method for storing only one copy of each distinct value:
fun main(vars: Array<String>) {
println(firstLine.intern() === firstLine.intern())
}
Here's the output:
true
You shouldn't abuse this method because the String pool is stored in the Permanent Generation section of the heap. And it can be collected only during major garbage collection.
- 微服務設計(第2版)
- 零基礎學C++程序設計
- MySQL數據庫應用與管理 第2版
- Vue.js前端開發基礎與項目實戰
- Clojure for Domain:specific Languages
- Apache Spark 2 for Beginners
- jQuery從入門到精通 (軟件開發視頻大講堂)
- Building a Recommendation Engine with Scala
- Hands-On Functional Programming with TypeScript
- Swift 4從零到精通iOS開發
- QlikView Unlocked
- Python預測分析實戰
- Docker on Windows
- C語言程序設計
- INSTANT Eclipse Application Testing How-to