Java9後String的空間優化

前言

據我所知 Java 開發人員幾乎任什麼時候候都會想到 String,字符串確實已經成爲最經常使用的類了,並且是大量使用。咱們都知道,String 實際上是封裝了字符,裏面必須由字符或字節數組來存放,從 Java9 開始 Java 語言開發者對 String 作了一些空間的優化。數組

從char到byte

JDK9 以前的庫的 String 類的實現使用了 char 數組來存放字符串,char 佔用16位,即兩字節。bash

private final char value[];
複製代碼

這種狀況下,若是咱們要存儲字符A,則爲0x00 0x41,此時前面的一個字節空間浪費了。但若是保存中文字符則不存在浪費的狀況,也就是說若是保存 ISO-8859-1 編碼內的字符則浪費,以外的字符則不會浪費。併發

而 JDK9 後 String 類的實現使用了 byte 數組存放字符串,每一個 byte 佔用8位,即1字節。機器學習

private final byte[] value
複製代碼

編碼

String 支持多種編碼,但若是不指定編碼的話,它可能使用兩種編碼,分別爲 LATIN1 和 UTF16。LATIN1 可能比較陌生,其實就是 ISO-8859-1 編碼,屬於單字節編碼。而 UTF16 爲雙字節編碼,它使用1個或2個16位長的空間存儲。分佈式

壓縮空間

壓縮的字符對象主要是在 ISO-8859-1 編碼內的字符,好比英語字母數字還有其餘常見符號。爲了更好理解咱們看下圖,假如咱們有一個「what」字符串,那麼若是在 Java9 以前,它的存儲是按以下隊列排列的,能夠看到每一個字符都須要16位來存儲,而高字節位都爲0,這個其實就是浪費了。佈局

這裏寫圖片描述

而在 Java9 後,它的存儲的排列則很緊湊了,以下圖,只需四個字節便可。學習

這裏寫圖片描述

但若是是「哈a」,則佈局爲下圖,因此若是字符串中的字符一旦包含了不在 ISO-8859-1 編碼內的字符,則一樣仍是統一使用16位長度來保存。優化

這裏寫圖片描述

Java9 的 String 默認是使用了上述緊湊的空間佈局的,看以下代碼,默認將 COMPACT_STRINGS 設置爲 true。而若是要取消緊湊的佈局能夠經過配置 VM 參數-XX:-CompactStrings實現。ui

static final boolean COMPACT_STRINGS;
static {
    COMPACT_STRINGS = true;
}
複製代碼

字符串長度

由於改變了 String 的實現,使用了 UTF-16 或 LATIN-1 編碼,因此內部須要一個標識coder來表示使用了哪一種編碼,LATIN1 值爲0,UTF16 值爲1。編碼

private final byte coder;
static final byte LATIN1 = 0;
static final byte UTF16  = 1;
複製代碼

而字符串的長度也與編碼相關,計算時經過右移來實現。若是是 LATIN-1 編碼,則右移0位,數組長度即爲字符串長度。而若是是 UTF16 編碼,則右移1位,數組長度的二分之一爲字符串長度。

public int length() {
    return value.length >> coder();
}
複製代碼

總結

字符串對象是 Java 中大量使用的對象,並且咱們會輕易大量使用它而從不考慮它的代價,因此對其的空間優化是有必要的,Java9 開始對 這能幫助咱們減小字符串在堆中佔用的空間,並且還能減輕GC壓力。同時也能看到該空間優化對中文來講意義不大。

-------------推薦閱讀------------

個人2017文章彙總——機器學習篇

個人2017文章彙總——Java及中間件

個人2017文章彙總——深度學習篇

個人2017文章彙總——JDK源碼篇

個人2017文章彙總——天然語言處理篇

個人2017文章彙總——Java併發篇


跟我交流,向我提問:

這裏寫圖片描述

公衆號的菜單已分爲「讀書總結」、「分佈式」、「機器學習」、「深度學習」、「NLP」、「Java深度」、「Java併發核心」、「JDK源碼」、「Tomcat內核」等,可能有一款適合你的胃口。

爲何寫《Tomcat內核設計剖析》

歡迎關注:

這裏寫圖片描述
相關文章
相關標籤/搜索