實例解析Java字符串內存管理方法
大?。?/span>0.3 MB 人氣: 2017-10-27 需要積分:1
通過對Java中字符串操作接口的分析可以發現,隨著這些操作的運行會產生較多的無用字符串,它們不再被Java類封裝并且也不被任何變量引用。這些無用字符串數據將一直停留在活躍堆中,直到Java虛擬機啟動垃圾收集將其回收。而由于字符串數據具有單個對象占用空間較小但總體數量很大的特征,大量的無用字符串數據不僅會影響堆空間的利用率,并且對Java虛擬機垃圾收集的性能有較大影響。
當前對Java中字符串的內存管理優化方案主要關注于字符串的使用效率上,如消除常量重復、延遲分配等技術[2],通過修改Java虛擬機對字符串分配回收的支持來提高堆中字符串的使用效率。然而這些方案無法處理堆中已經成為無用字符串的數據,只能等待垃圾收集來處理。
近期編譯時的獨立對象回收策略[3]則專注于在編譯階段對應用程序做分析并插入回收指令以回收無用對象空間,但是該方案對Java庫函數只做保守分析從而無法回收這些無用字符串。為此,本文從對字符串操作接口的分析出發,識別各類操作對字符串的改變情況以利用獨立對象回收策略中的指令插樁技術來主動回收無用字符串對象,以提高堆空間的利用率、減低垃圾回收的負擔、改善Java虛擬機的性能。
1 Java中字符串的支持與分析
1.1 Java中字符串的支持
Java語言將字符串的表示和操作都封裝在StringBuilder、StringBuffer和String三個類中。其中前兩個類指向的字符串是可變的,String類指向的字符串是不變的。這三個類的內部結構基本上一致,以StringBuilder為例,StringBuilder在Java中的結構如圖1所示。
從圖1可以看出,字符串數據由StringBuilder對象指向的value域保存,在內存空間上反映為兩個對象:StringBuilder對象通過value域指向字符串對象。由于該類提供常用的可變字符串操作接口且相對另一個類StringBuffer具有較高的執行效率,對字符串數據的操作在Java虛擬機中一般會將其轉換為StringBuilder對象再做處理。下面以一個語句示例來說明這一點:
String s=new String(‘aa’+’bb’+’cc’);
該語句的語義是將三個字符串連接在一起并生成一個String對象,在Java語言的源程序級別上不會出現StringBuilder對象,但是經過編譯器優化之后,這條語句實際被翻譯為下面的字節碼形式(為簡化描述,本文以源語言來表示字節碼的操作):
StringBuilder t=new StringBuilder(‘aa’);
t.append(‘bb’);
t.append(‘cc’);
String s=t.toString();
即Java編譯器會首先創建一個StringBuilder對象,完成字符串的連接工作之后再將其轉變為String對象。由于類似于這種情況的字符串操作較多地出現在輸出方法和字符串創建方法中,所以可推斷出StringBuilder有著較大的使用頻率,故將以其為代表分析其提供的接口對字符串的影響。
1.2 無用字符串的產生
在上節的示例中,StringBuilder類提供的append()接口將會改變value域所指向的字符串,其做法是:新建長度為連接后字符串長度之和的字符數組,分段復制之后使其成為value域指向的新數組,而value域指向的原數組將被丟棄成為無用字符串。
圖2為示例語句中append()接口引起的value域指向字符串變化圖。
從圖2可以看出,在append()接口執行過后,對象的字符數組將指向新建的字符串’aabb’,原有字符串’aa’將不被任何變量指向而成為無用字符串。
非常好我支持^.^
(0) 0%
不好我反對
(0) 0%