Mục lục
String được sử dụng rất nhiều trong ngôn ngữ java, trong bài viết này chúng ta sẽ cùng nhau tìm hiểu về String pool – cơ chế lưu trữ string khi chúng được lưu bởi JVM.
String Interning
String trong java có tính chất immutable(bất biến) vì thế JVM có thể tối ưu hoá memory bằng cách chỉ lưu trữ một bản sao duy nhất của một string trong String pool quá trình này gọi là interning.
Khi bạn khởi tạo String bằng cách gán chúng bằng một chuỗi A nào đó ví dụ như
String str = "shareprogramming.net"
Thì JVM sẽ tiến hành tìm kiếm trong pool xem có một chuỗi nào đó có giá trị bằng A, nếu tìm thấy java compiler đơn giản là trả về tham chiếu đến địa chỉ của chuỗi được tìm thấy. Nếu không thì string object mới sẽ được khởi tạo và thêm vào pool.
String constantString1 = "shareprogramming.net"; String constantString2 = "shareprogramming.net"; assertThat(constantString1) .isSameAs(constantString2);
String constructor
Khi chúng ta khởi tạo 1 String bằng từ khoá new thì Java compiler sẽ luôn tạo mới một string object và lưu chúng vào vùng nhớ heap. Mọi String được khởi tạo bằng cách này đều có một vùng nhớ riêng cho nó cho dù giá trị giữa chúng là giống nhau.
String constantString = "shareprogramming.net"; String newString = new String("shareprogramming.net"); assertThat(constantString).isNotSameAs(newString);
String literal vs String object
Khi khởi tạo một String object vs từ khoá new() chúng ta sẽ luôn luôn khởi tạo một object mới vào heap memory. Mặt khác khi bạn khởi tạo String sử dụng String literal(Gán giá trị bằng cặp dấu “”) thì có thể object được trả về là một object đã tồn tại trước đó trong String pool nếu đã có object String có giá trị tương tự.
String literal và String object đều là các String object, điểm khác biệt duy nhất là khởi tạo từ new sẽ luôn khởi tạo một object mới còn lại chúng có thể sử dụng lại các object String được khởi tạo trước đó.
Ví dụ để so sánh 2 object String literal chúng ta có thể sử dụng dấu “==” như sau vì chúng sẽ cùng một vùng nhớ.
public class Main { public static void main(String[] args) { String str1 = "shareprogramming.net"; String str2 = "shareprogramming.net"; System.out.println(str1 == str2); // true } }
Cũng với ví dụ trên nếu chúng ta khởi tạo 2 String object với từ khoá new()
public class Main { public static void main(String[] args) { String str1 = new String("shareprogramming.net"); String str2 = new String("shareprogramming.net"); System.out.println(str1 == str2); // false } }
Chúng ta cũng không thể so sánh một String literal với String object.
public class Main { public static void main(String[] args) { String str1 = new shareprogramming.net"; String str2 = new String("shareprogramming.net"); System.out.println(str1 == str2); // false } }
Manual Interning
Bạn cũng có thể tự thêm một String object vào String pool bằng cách gọi method intern() trên một String object bạn muốn.
Việc làm trên sẽ tự động thêm String object vào String pool và sử dụng cho các trường hợp sau này.
public class Main { public static void main(String[] args) { String str1 = "shareprogramming.net"; String str2 = new String("shareprogramming.net"); String internedString = str2.intern(); System.out.println(str1 == internedString); } }
Garbage Collection
Từ java 7 trở về trước JVM lưu String pool trong vùng nhớ được gọi là PermGen nó có kích thước cố định và không thể mở rộng tại thời điểm runtime và không được trình dọn rác thu gon.
Vì vậy chúng ta sẽ thường xuyên gặp lỗi OutOfMemory error từ JVM khi chúng ta có quá nhiều String trong vùng nhớ PermGen.
Thật may rằng từ java 7 trở đi, java đã lưu trữ String Pool trong vùng nhớ Heap và sẽ được trình dọn rác can thiệp khi không có một biến nào tham chiếu đến nó. Nhờ vậy chúng ta sẽ giảm bớt khả năng gặp lỗi OutOfMemory.
Nguồn tham khảo