Java의 끈 상수 풀
Java에는 두 가지 형태의 문자열 객체 생성이 있습니다. 하나는 String str = "droid"와 같은 문자 형태입니다. 다른 하나는 string str = new String ( "droid"); 우리는 종종 코드, 특히 문자 그대로의 방법을 작성할 때이 두 가지 방법을 사용합니다. 그러나이 두 구현은 실제로 성능 및 메모리 사용에 약간의 차이가 있습니다. 이 모든 것은 JVM이 문자열 상수 풀 또는 문자열 리터럴 풀인 문자열 객체의 반복적 인 생성을 줄이기 위해 특별한 메모리를 유지한다는 사실 때문입니다.
작동 방식
문자열 객체가 코드의 문자 형식으로 생성되면 JVM은 먼저 리터럴을 확인합니다. 문자열 상수 풀에 동일한 내용이있는 문자열 객체에 대한 참조가 있으면 참조가 반환됩니다. 그렇지 않으면 새 문자열 객체가 생성되고 참조가 문자열 상수 풀에 배치되고 참조가 반환됩니다.
예를 들어보세요
문자 그대로의 창조 형식
문자열 str1 = "droid";
JVM은이 문자를 감지합니다. 여기서 우리는 콘텐츠가있는 객체가 드로이드가 없다고 생각합니다. JVM은 문자열 상수 풀을 통해 드로이드 컨텐츠가있는 문자열 객체를 찾을 수 없으므로이 문자열 객체를 생성 한 다음 방금 만든 객체의 참조를 문자열 상수 풀에 넣고 변수 str1에 대한 참조를 반환합니다.
다음에 이와 같은 코드가 있다면
문자열 str2 = "droid";
마찬가지로 JVM은 여전히이 문자를 감지해야합니다. String Constant Pool을 검색함으로써 JVM은 내용이 "드로이드"문자열 객체가 존재한다는 것을 발견하므로 기존 문자열 객체의 참조를 변수 str2에 반환합니다. 새 문자열 객체는 여기에서 재현되지 않습니다.
str1과 str2가 동일한 객체를 가리키는 지 확인하면이 코드를 사용할 수 있습니다.
System.out.println (str1 == str2);
결과는 사실입니다.
새로 만들어냅니다
문자열 str3 = 새 문자열 ( "droid");
새로운 사용을 사용하여 문자열 객체를 구성하면 문자열 상수 풀에 동일한 내용이있는 객체에 대한 참조가 있는지 여부에 관계없이 새 문자열 객체가 생성됩니다. 다음 코드를 사용하여 테스트하겠습니다.
문자열 str3 = 새 문자열 ( "droid");
System.out.println (str1 == str3);
결과는 우리가 생각하는대로 거짓이며 두 변수가 다른 객체를 가리 킵니다.
인턴
위의 새로 생성 된 문자열 객체의 경우 String Constant Pool에 대한 참조를 추가하려면 인턴 메소드를 사용할 수 있습니다.
인턴에 전화 한 후 먼저 String Constant Pool의 개체에 대한 참조가 있는지 확인하십시오. 존재하는 경우이 참조를 변수에 반환하면 참조가 추가되어 변수로 반환됩니다.
문자열 str4 = str3.intern ();
System.out.println (str4 == str1);
출력 결과는 사실입니다.
어려운 문제
전제 조건?
String Constant Pools를 구현하기위한 전제 조건은 Java의 String Object가 불변이므로 여러 변수가 동일한 객체를 안전하게 공유 할 수 있다는 것입니다. Java의 문자열 객체가 가변적이고 하나의 참조 작업이 객체의 값을 변경하면 다른 변수도 영향을받습니다. 분명히 불합리합니다.
참조 또는 객체
이 질문은 문자열 상수 풀이 참조 또는 객체에 저장 될 때 가장 일반적입니다. String Constant Pool은 객체가 아니라 객체 참조를 저장합니다. Java에서는 힙 메모리로 객체가 생성됩니다.
업데이트 확인, 수신 된 많은 의견 도이 문제에 대해 논의하고 있으며 간단히 확인합니다. 환경을 확인하십시오
22 : 18 : 54 Androidyue ~/videos $ cat/etc/os-releaseName = fedoraversion = "17 (Beefy Miracle)"id = fedoraversion_id = 17pretty_name = "Fedora 17 (Beefy 기적) "ansi_color ="0; 34 "cpe_name ="cpe :/o : Fedoraproject : Fedora : 17 "22 : 04 Androidyue ~/videos $ java -versionjava 버전"1.7.0_25 "Openjdk 런타임 환경 (Fedora-2.3.12.12.12.12.12.12.12. VM (빌드 23.7-b01, 혼합 모드)
검증 아이디어 : 다음 Java 프로그램은 82m 크기의 비디오 파일을 읽고 문자열 형태로 인턴 작전을 수행합니다.
22 : 01 : 17 Androidyue ~/비디오 $ ll -lh | grep why_to_learn.mp4-rw-rw-r--. 1 Androidyue Androidyue 82m 2013 년 10 월 20 일 Why_to_learn.mp4
확인 코드
import java.io.bufferedReader; import java.io.filenotfoundException; import java.io.filereader; import java.io.ioexception; public class testmain {private static string filecontent; public static void main (String [] args) {filecontent = readFileToString (args [0]); if (null! = filecontent) {filecontent = filecontent.intern (); System.out.println ( "NOT NULL"); }} private static string readFileToString (문자열 파일) {bufferedReader reader = null; try {reader = new bufferedReader (new Filereader (파일)); StringBuffer buff = new StringBuffer (); 문자열 라인; while ((line = reader.readline ())! = null) {buff.append (line); } return buff.toString (); } catch (filenotfoundException e) {e.printstacktrace (); } catch (ioexception e) {e.printstacktrace (); } 마침내 {if (null! = reader) {try {reader.close (); } catch (ioexception e) {e.printstacktrace (); }}} return null; }}끈 상수 풀은 힙 메모리의 영구 생성에 존재하기 때문에 Java 8 이전에는 적합합니다. 작은 값의 영구 생성을 설정하여 확인합니다. 문자열 객체가 문자열 상수 풀에 존재하는 경우 java.lang.outofMemoryError permgen 공간 오류를 던져야합니다.
java -xx : permsize = 6m testmain ~/videos/why_to_learn.mp4
증명 프로그램을 실행하는 것은 OOM을 던지지 않지만 이는 객체 나 참조로 저장되었음을 증명할 수 없습니다.
그러나 이것은 적어도 문자열의 실제 콘텐츠 객체 char []가 문자열 상수 풀에 저장되지 않았 음을 증명합니다. 이 경우 String Constant Pool이 문자열 객체 또는 문자열 객체에 대한 참조를 저장하는 것이 중요하지 않습니다. 그러나 개인은 여전히 참고 문헌을 저장하는 경향이 있습니다.
장단점
문자열 상수 풀링의 장점은 동일한 컨텐츠의 문자열 생성을 줄이고 메모리 공간을 절약하는 것입니다.
단점을 말해야한다면 CPU 컴퓨팅 시간을 교환하기위한 CPU 컴퓨팅 시간을 희생하는 것입니다. CPU 계산 시간은 주로 문자열 상수 풀에 동일한 내용이있는 객체에 대한 참조가 있는지 여부를 찾는 데 주로 사용됩니다. 그러나 내부 구현은 해시 가능이므로 계산 비용은 낮습니다.
GC 재활용?
문자열 상수 풀이 공유 문자열 객체에 대한 참조를 보유하고 있기 때문에 이것이 이러한 객체를 재활용 할 수 없다는 것을 의미합니까?
우선, 문제의 공유 객체는 일반적으로 더 작습니다. 내가 확인한 한, 이전 버전에는 실제로 그러한 문제가 있었지만 약한 참고 문헌이 도입 되면서이 문제는 현재 사라져야합니다.
이 문제와 관련 하여이 기사에 대해 자세히 알아볼 수 있습니다. 인턴 줄 : Java 용어집
인턴을 사용 하시겠습니까?
인턴 사용의 전제 조건은 인턴을 사용해야한다는 것입니다. 예를 들어, 우리는 여기에 수백만의 레코드가 있으며, 여기서 레코드의 특정 가치는 미국 캘리포니아 주입니다. 우리는 그러한 문자열 객체를 수백만으로 만들고 싶지 않습니다. 인턴을 사용하여 하나의 사본 만 메모리에 보관할 수 있습니다. 인턴에 대한 심층적 인 이해는 String#Intern의 심층 분석을 참조하십시오.
항상 예외가 있습니까?
다음 코드가 여러 문자열 객체를 생성하고 문자열 상수 풀에 여러 참조를 저장한다는 것을 알고 있습니까?
문자열 test = "a" + "b" + "c";
대답은 하나의 객체 만 생성되고 상수 풀에서 하나의 참조 만 저장된다는 것입니다. 우리는 Javap 디 컴파일을 사용하고 그것을 살펴 봅니다.
17:02 $ javap -c "testinternedpoolgc.java"에서 공개 클래스 testinternedpoolgc에서 java.lang.object {public testinternedpoolgc (); 코드 : 0 : aload_0 1 : invokescial #1; // 메소드 java/lang/object. "<init>":() v 4 : returnpublic static void main (java.lang.string [])은 java.lang.exception을 던졌습니다. 코드 : 0 : LDC #2; // 문자열 ABC 2 : Store_1 3 : 리턴당신은 그것을 보셨습니까? 실제로, 편집 기간 동안,이 3 개의 리터럴은 하나로 합성되었습니다. 이것은 실제로 중복 문자열 객체를 생성하지 않고 문자열 스티칭 문제가없는 최적화입니다. 문자열 스티칭의 경우 Java 세부 사항을 볼 수 있습니다 : String Stitching.
위는 Java의 String Constant Pool에 대한 정보를 편집 한 것입니다. 우리는 향후 관련 정보를 계속 추가 할 것입니다. 이 사이트를 지원 해주셔서 감사합니다!