官术网_书友最值得收藏!

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.

主站蜘蛛池模板: 广宁县| 襄汾县| 石门县| 百色市| 光泽县| 曲麻莱县| 裕民县| 闽侯县| 巴彦淖尔市| 杭州市| 缙云县| 登封市| 盐源县| 宁波市| 英吉沙县| 玉林市| 丁青县| 兖州市| 小金县| 澎湖县| 成安县| 天等县| 安新县| 嘉义县| 高淳县| 长岭县| 从化市| 夏邑县| 许昌县| 崇阳县| 永春县| 吴旗县| 郁南县| 府谷县| 丰顺县| 甘南县| 和静县| 筠连县| 右玉县| 九寨沟县| 桃园市|