JavaRush /Blog Java /Random-VI /chuỗi con(..) ám ảnh tôi
IgorBrest
Mức độ

chuỗi con(..) ám ảnh tôi

Xuất bản trong nhóm
Thực ra vì lý do của chủ đề nên tôi đã cho phép mình đi sâu vào String.substring(..). Và có lẽ tôi đã đạt được những kết quả không ngờ tới, điều mà tôi quyết định chia sẻ với các bạn, những người Javorashovite thân mến. Trình bày nó theo sự phán xét của bạn, có thể nói như vậy. Vì vậy, nó ở đây. Có một câu lệnh rằng một chuỗi được tạo bằng phương thức chuỗi con (..) sử dụng mảng ký tự của chuỗi gốc. Đặc biệt, đây là một đoạn trích từ bài viết được đọc gần đây “Java Reference. Static Strings” của các bài báo có uy tín :
Có một lưu ý về phương thức chuỗi con - chuỗi trả về sử dụng cùng một mảng byte với chuỗi gốc
Và tất nhiên, Bài giảng Javarash. Dưới đây là trích dẫn từ ngày 22 tháng 12:
Khi chúng ta tạo một chuỗi con bằng phương thức chuỗi con, một đối tượng String mới sẽ được tạo. Nhưng thay vì lưu trữ một tham chiếu đến một mảng với một bộ ký tự mới, đối tượng này lưu trữ một tham chiếu đến mảng ký tự cũ và đồng thời lưu trữ hai biến để xác định phần nào của mảng ký tự gốc thuộc về nó. ... Khi một chuỗi con được tạo, mảng ký tự không được sao chép sang đối tượng Chuỗi mới. Thay vào đó, cả hai đối tượng đều lưu trữ một tham chiếu đến cùng một mảng ký tự. Nhưng! Đối tượng thứ hai lưu trữ thêm hai biến, chứa biến nào và bao nhiêu ký tự của mảng này được ghi vào nó. ... Do đó, nếu bạn lấy một chuỗi dài 10.000 ký tự và tạo 10.000 chuỗi con có độ dài bất kỳ từ chuỗi đó, thì những “chuỗi con” này sẽ chiếm rất ít bộ nhớ, bởi vì mảng ký tự không bị trùng lặp. Các chuỗi chiếm nhiều dung lượng sẽ chỉ chiếm một vài byte.
mọi thứ đều được viết rõ ràng, thậm chí được nhai. Tuy nhiên, vì tôi đang cố gắng nâng cao kiến ​​​​thức tiếng Anh của mình nên tôi thường tìm đến các tài liệu chính thức và không hiểu sao tôi không thể tìm thấy sự xác nhận nào về sự thật này... Cho rằng điều này là do sự bất cẩn của mình, tôi vẫn xem mã nguồn của substring() (nhờ IDEA cho phép bạn thực hiện việc này chỉ bằng một cú nhấp chuột). public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > value.length) { throw new StringIndexOutOfBoundsException(endIndex); } int subLen = endIndex - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); } Tò mò, tôi đã đi xa hơn: * Allocates a new {@code String} that contains characters from a subarray * of the character array argument. The {@code offset} argument is the * index of the first character of the subarray and the {@code count} * argument specifies the length of the subarray. The contents of the * subarray are copied; subsequent modification of the character array does * not affect the newly created string. public String(char value[], int offset, int count) { if (offset < 0) { throw new StringIndexOutOfBoundsException(offset); } if (count < 0) { throw new StringIndexOutOfBoundsException(count); } // Note: offset or count might be near -1>>>1. if (offset > value.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } this.value = Arrays.copyOfRange(value, offset, offset+count); } trong đó Arrays.copyOfRange là một phương thức gốc trả về bản sao của một mảng từ char... Mã khá tầm thường và đối với tôi, rõ ràng là một hàng mới với một bộ ký tự mới được tạo một cách đơn giản. hoặc tôi đã không tính đến điều gì đó... Vì vậy, không hoàn toàn tin vào kết luận của mình, tôi quyết định bằng cách nào đó kiểm tra chuỗi con này(), dựa vào một cụm từ trong bài giảng:
Do đó, nếu bạn lấy một chuỗi dài 10.000 ký tự và tạo ra 10.000 chuỗi con có độ dài bất kỳ từ chuỗi đó thì những “chuỗi con” này sẽ chiếm rất ít bộ nhớ...
chỉ thay vì 10_000 chúng ta sẽ kiếm ngay 100_000_000, tại sao phải lãng phí thời gian vào những chuyện vặt vãnh. Tôi nhanh chóng đưa vào đoạn mã sau: và đây là điều đã xảy ra: tức là. Mỗi khi bạn tạo một chuỗi con mới bằng cách sử dụng bigString.substring(..), mảng ký tự sẽ bị NHÂN ĐÔI. Làm thế nào khác chúng ta có thể giải thích sự gia tăng tiêu thụ bộ nhớ như vậy? Sau này, cá nhân tôi không còn nghi ngờ gì về hoạt động của phương thức String.substsring(). Còn bạn thì sao? public class Test { public static void main(String[] args) { System.out.println("Начинаем:"); print(); System.out.println("********************************"); char[]big=new char[100_000_000];//создаем нормальный такой массив int j=0;//и заполняем этот массив всякой ерундой for (int k=0;k list=new ArrayList<>();//здесь будут ссылки на строки, что бы сборщик мусора не удалял //не используемые, по его мнению, строки. System.out.println("************************************"); System.out.println("Теперь будем создавть подстроки с помощью substring(..) и наблюдать," + "что же происходит с памятью"); for (int i = 2; i <10; i++) { //создаем подстроку, используя метод String.substring(..) String sub= bigString.substring(1,bigString.length()-1); //если этот метод не создает fully новый массив символов, а только пользуется //исходным из bigString // то при создании новой строки sub мы не будем наблюдать ощутипый расход памяти list.add(sub);//эти ссылки мы должны где нибудь хранить, иначе сборщик мусора //избавится от неипользуемых объктов String System.out.print(String.format("Создаем %d-ую подстроку, при этом ", i - 1)); print(); } System.out.println("***************************************"); print(); } static void print(){ System.out.println("Памяти используется "+(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())/1024/1024 + " mb"); } } Начинаем: Памяти используется 0 mb ******************************** создал большую строку bigString на основе массива big. Теперь: Памяти используется 382 mb ************************************ Теперь будем создавть подстроки с помощью substring(..) и наблюдать,что же происходит с памятью Добавляем 1-ую подстроку, при этом Памяти используется 573 mb Добавляем 2-ую подстроку, при этом Памяти используется 763 mb Добавляем 3-ую подстроку, при этом Памяти используется 954 mb Добавляем 4-ую подстроку, при этом Памяти используется 1145 mb Добавляем 5-ую подстроку, при этом Памяти используется 1336 mb Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOfRange(Arrays.java:3658) at java.lang.String. (String.java:201) at java.lang.String.substring(String.java:1956) at com.javarush.test.tests.Test.main(Test.java:42) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) Process finished with exit code 1
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION