Java의 문자열 상수 풀 상세 정보

Java의 문자열 상수 풀
Java에서 문자열 객체는 두 가지 형식으로 만들어집니다. 하나는 문자열 형식입니다. 예를 들어 Stringstr = "droid",다른 하나는 new와 같은 표준적인 구조 대상을 사용하는 방법이다. 예를 들어 Stringstr=newString("droid"),이 두 가지 방식은 우리가 코드를 작성할 때 자주 사용하는데, 특히 글자 양의 방식은 그렇다.그러나 이 두 가지 실현에는 사실 일부 성능과 메모리 점용의 차이가 존재한다.이 모든 것은 JVM이 문자열 객체의 반복 생성을 줄이기 위해 특수한 메모리를 유지했기 때문입니다. 이 메모리는 문자열 상수 탱크나 문자열 글꼴 탱크가 됩니다.
작업 원리
코드에 문자열 객체를 만드는 문자 양이 나타나면 JVM은 먼저 이 문자 양을 검사합니다. 문자열 상수 풀에 같은 내용의 문자열 객체에 대한 참조가 있으면 이 참조를 되돌려줍니다. 그렇지 않으면 새 문자열 객체가 만들어지고 이 참조를 문자열 상수 풀에 넣고 다시 되돌려줍니다.
예를 들어 설명하다
글꼴 생성 형식
String str1 = "droid";
JVM은 이 글꼴을 검사합니다. 여기에는 droid라는 객체가 존재하지 않습니다.JVM은 문자열 상수 풀을 통해 droid라는 문자열 객체가 존재하는 것을 찾을 수 없습니다. 그러면 이 문자열 대상을 만들고 새로 만든 대상의 인용을 문자열 상수 풀에 넣고 변수str1에 되돌려줍니다.
하면, 만약, 만약...
String str2 = "droid";
마찬가지로 JVM은 이 글자의 양을 검사해야 합니다. JVM은 문자열 상수 탱크를 찾아서'droid'라는 문자열 대상이 존재하는 것을 발견하고 이미 존재하는 문자열 대상의 인용을 변수str2에 되돌려줍니다.새 문자열 대상을 다시 만들지 않습니다.
str1과str2가 같은 대상을 가리키는지 확인하십시오. 이 코드를 통해
System.out.println(str1 == str2);
결과는true입니다.
new로 만들기
String str3 = new String("droid");
우리가 new를 사용하여 문자열 대상을 구성할 때, 문자열 상량 탱크에 같은 내용의 대상이 인용되었든 없든 간에 새로운 문자열 대상은 생성됩니다.그래서 다음 코드로 테스트를 해보겠습니다.
String str3 = new String("droid");
System.out.println(str1 == str3);
결과는 우리가 생각한 바와 같이false로 이 두 변수가 가리키는 것이 서로 다른 대상임을 나타낸다.
intern
위에서 new로 만든 문자열 대상에 대해 이 대상의 인용을 문자열 상수 탱크에 추가하려면intern 방법을 사용할 수 있습니다.
intern을 호출한 후, 우선 문자열 상량 탱크에 이 대상의 인용이 있는지 확인하고, 만약 존재한다면, 이 인용을 변수에 되돌려주고, 그렇지 않으면 인용을 추가하여 변수에 되돌려줍니다.
String str4 = str3.intern();
System.out.println(str4 == str1);
출력된 결과는true입니다.
난제
전제 조건?
문자열 상수 풀이 구현되는 전제 조건은 Java의 String 객체가 변경될 수 없다는 것입니다. 이렇게 하면 여러 변수가 같은 객체를 공유할 수 있습니다.만약 자바의 String 대상이 변할 수 있다면, 인용 조작이 대상의 값을 바꾸면, 다른 변수도 영향을 받을 것이다. 분명히 이것은 불합리한 것이다.
참조 or 객체
문자열 상량 탱크에 저장된 인용인지 대상인지, 이 문제가 가장 흔하다.문자열 상수 탱크는 대상 인용이지 대상이 아닙니다.Java에서 객체는 더미 메모리에 생성됩니다.
업데이트 검증, 많은 댓글도 이 문제를 토론하고 있습니다. 저는 간단하게 검증을 진행했습니다.환경 확인

22:18:54-androidyue~/Videos$ cat /etc/os-release
NAME=Fedora
VERSION="17 (Beefy Miracle)"
ID=fedora
VERSION_ID=17
PRETTY_NAME="Fedora 17 (Beefy Miracle)"
ANSI_COLOR="0;34"
CPE_NAME="cpe:/o:fedoraproject:fedora:17"

22:19:04-androidyue~/Videos$ java -version
java version "1.7.0_25"
OpenJDK Runtime Environment (fedora-2.3.12.1.fc17-x86_64)
OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)

검증 사고방식: 다음 자바 프로그램은 82M 크기의 비디오 파일을 읽고 문자열 형식으로intern 작업을 합니다.

22:01:17-androidyue~/Videos$ ll -lh | grep why_to_learn.mp4
-rw-rw-r--. 1 androidyue androidyue 82M Oct 20 2013 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(String file) {
   BufferedReader reader = null;
   try {
     reader = new BufferedReader(new FileReader(file));
     StringBuffer buff = new StringBuffer();
     String line;
     while ((line = reader.readLine()) != null) {
       buff.append(line);
     }
     return buff.toString();
   } catch (FileNotFoundException e) {
     e.printStackTrace();
   } catch (IOException e) {
     e.printStackTrace();
   } finally {
     if (null != reader) {
       try {
         reader.close();
       } catch (IOException e) {
         e.printStackTrace();
       }
     }
   }
   return null;
 }
}

문자열 상수 탱크는 메모리에 영구적으로 존재하기 때문에 자바8 이전에 적용됩니다.우리는 영구적으로 아주 작은 값을 대신해서 검증을 진행한다.만약 문자열 대상이 문자열 상량 탱크에 존재한다면, 필연적으로java를 던질 것이다.lang.OutOfMemoryError permgen space 오류.
java -XX:PermSize=6m TestMain ~/Videos/why_to_learn.mp4
실행 증명 프로그램이 OOM을 던지지 않았습니다. 사실 이것은 저장된 것이 대상인지 인용인지 잘 증명할 수 없습니다.
그러나 이것은 적어도 문자열의 실제 내용 대상인char[]가 문자열 상량 탱크에 저장되지 않는다는 것을 증명한다.그렇다면 문자열 상량 탱크가 문자열 대상을 저장하는지 문자열 대상의 인용인지는 오히려 그렇게 중요하지 않다.그러나 개인은 여전히 인용을 위해 저장하는 경향이 있다.
장단점
문자열 상량 탱크의 장점은 같은 내용의 문자열 생성을 줄이고 메모리 공간을 절약하는 것이다.
굳이 폐단을 말하자면 CPU 계산 시간을 희생해 공간을 바꾸는 것이다.CPU 계산 시간은 문자열 상수 풀에서 컨텐트가 같은 객체에 대한 참조가 있는지 확인하는 데 주로 사용됩니다.그러나 그 내부는 HashTable로 이루어져 계산 원가가 비교적 낮다.
GC 회수?
문자열 상량 탱크에 공유된 문자열 대상의 인용이 있기 때문에, 이것이 바로 이 대상들을 회수할 수 없게 하는 것입니까?
우선 문제에서 공유하는 대상은 일반적으로 비교적 작다.내가 조사한 바에 의하면 초기 버전에서 확실히 이런 문제가 존재했지만 약한 인용이 도입되면서 현재 이 문제는 없을 것이다.
이 문제에 관해서는 이 문장의 interned Strings: Java Glossary를 구체적으로 이해할 수 있다
intern 사용?
인터넷을 사용하는 전제는 당신이 확실히 사용해야 한다는 것을 잘 알고 있다는 것이다.예를 들어 우리는 수백만 개의 기록을 가지고 있다. 그 중에서 기록된 어떤 값은 미국 캘리포니아주에 여러 번 있다. 우리는 수백만 개의 문자열 대상을 만들고 싶지 않다. 우리는 intern을 사용하여 메모리에 한 개만 보존하면 된다.intern에 대한 자세한 내용은 String#intern 을 참조하십시오.
항상 예외가 있습니까?
다음 코드가 몇 개의 문자열 대상을 만들고 문자열 상수 탱크에 몇 개의 인용을 저장하는지 아십니까?
String test = "a"+ "b"+ "c";
답은 하나의 대상만 만들고 상량 탱크에도 인용만 저장하는 것입니다.우리는javap반컴파일을 사용하여 한 번 보면 알 수 있다.

17:02 $ javap -c TestInternedPoolGC
Compiled from "TestInternedPoolGC.java"
public class TestInternedPoolGC extends java.lang.Object{
public TestInternedPoolGC();
 Code:
  0: aload_0
  1: invokespecial  #1; //Method java/lang/Object."<init>":()V
  4: return

public static void main(java.lang.String[])  throws java.lang.Exception;
 Code:
  0: ldc #2; //String abc
  2: astore_1
  3: return

보셨습니까? 실제로 번역하는 동안 이 세 글자의 양을 합성했습니다.이렇게 하는 것은 사실상 일종의 최적화로 여분의 문자열 대상을 만드는 것을 피하고 문자열 결합 문제도 발생하지 않았다.문자열 맞춤법 정보는 Java 세부 정보: 문자열 맞춤법을 볼 수 있습니다.
이상은 자바에 있는 문자열 상량 탱크에 대한 자료 정리입니다. 다음에 관련 자료를 계속 보충합니다. 본 사이트에 대한 지지에 감사드립니다!

좋은 웹페이지 즐겨찾기