Java에서 문자열 재정의 특성 소개

4430 단어 Java문자열 리셋
문자열은 모든 응용 프로그램에서 대량의 메모리를 차지한다.특히 독립된 UTF-16 문자를 포함하는 char[] 수조는 JVM 메모리에 가장 많은 기여를 한다. 왜냐하면 문자당 2자리를 차지하기 때문이다.
메모리의 30%가 문자열에 소모되는 것은 사실 매우 흔한 일이다. 문자열이 우리와 상호작용하는 가장 좋은 형식일 뿐만 아니라 유행하는 HTTP API가 대량의 문자열을 사용했기 때문이다.Java 8 Update 20을 사용하면 문자열 리셋이라는 새로운 기능을 접할 수 있습니다. 이 기능은 G1 쓰레기 수거기가 필요합니다. 쓰레기 수거기는 기본적으로 닫힙니다.
문자열은 문자열 내부가 실제적으로char수조이고final의 특성을 재사용하기 때문에 JVM은 임의로 그들을 조종할 수 있다.
문자열을 중시하기 위해 개발자는 대량의 전략을 고려했지만 최종적으로 다음과 같은 방식을 채택했다.
쓰레기 수거기가 String 대상에 접근할 때마다char 그룹에 표시를 합니다.이것은char수조의hashvalue를 가져와 수조에 대한 약한 인용과 함께 존재합니다.쓰레기 수거기에서 다른 문자열을 발견하면, 이 문자열과char수조가 같은hash코드를 가지고 있다면, 양자에 대해 한 문자와 한 문자의 비교를 할 수 있습니다.
만약 그들이 잘 일치한다면, 두 번째 문자열을 가리키는char수 그룹을 가리키는 문자열이 수정될 것이다.첫 번째char수조는 더 이상 인용되지 않고 회수될 수 있습니다.
이 전체 과정은 당연히 약간의 비용을 가져왔지만, 매우 튼튼한 상한선에 의해 통제되었다.예를 들어 문자가 중복된 것을 발견하지 못하면 한동안 검사되지 않습니다.
그렇다면 이 특성은 실제로 어떻게 일을 합니까?우선, 방금 발표된 Java 8 Update 20이 필요합니다. 그리고 이 설정에 따라: -Xmx256m-XX:+UseG1GC에서 다음 코드를 실행합니다.
 

public class LotsOfStrings {
 
 private static final LinkedList<String> LOTS_OF_STRINGS = new LinkedList<>();
 
 public static void main(String[] args) throws Exception {
  int iteration = 0;
  while (true) {
   for (int i = 0; i < 100; i++) {
    for (int j = 0; j < 1000; j++) {
     LOTS_OF_STRINGS.add(new String("String " + j));
    }
   }
   iteration++;
   System.out.println("Survived Iteration: " + iteration);
   Thread.sleep(100);
  }
 }
}
이 코드는 30개의 교체를 실행한 후에 OutOfMemoryError에 보고합니다.
이제 문자열을 다시 켜고 다음 설정을 사용하여 위 코드를 실행합니다.

-Xmx256m -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+PrintStringDeduplicationStatistics

이 때 그것은 이미 더 긴 시간을 운행할 수 있을 뿐만 아니라, 50개의 교체가 끝난 후에야 비로소 종료된다.
JVM은 현재 어떤 작업을 하고 있는지 함께 인쇄합니다.
 

[GC concurrent-string-deduplication, 4658.2K->0.0B(4658.2K), avg 99.6%, 0.0165023 secs]
  [Last Exec: 0.0165023 secs, Idle: 0.0953764 secs, Blocked: 0/0.0000000 secs]
   [Inspected:     119538]
     [Skipped:       0( 0.0%)]
     [Hashed:     119538(100.0%)]
     [Known:        0( 0.0%)]
     [New:       119538(100.0%)  4658.2K]
   [Deduplicated:    119538(100.0%)  4658.2K(100.0%)]
     [Young:       372( 0.3%)   14.5K( 0.3%)]
     [Old:       119166( 99.7%)  4643.8K( 99.7%)]
  [Total Exec: 4/0.0802259 secs, Idle: 4/0.6491928 secs, Blocked: 0/0.0000000 secs]
   [Inspected:     557503]
     [Skipped:       0( 0.0%)]
     [Hashed:     556191( 99.8%)]
     [Known:       903( 0.2%)]
     [New:       556600( 99.8%)   21.2M]
   [Deduplicated:    554727( 99.7%)   21.1M( 99.6%)]
     [Young:       1101( 0.2%)   43.0K( 0.2%)]
     [Old:       553626( 99.8%)   21.1M( 99.8%)]
  [Table]
   [Memory Usage: 81.1K]
   [Size: 2048, Min: 1024, Max: 16777216]
   [Entries: 2776, Load: 135.5%, Cached: 0, Added: 2776, Removed: 0]
   [Resize Count: 1, Shrink Threshold: 1365(66.7%), Grow Threshold: 4096(200.0%)]
   [Rehash Count: 0, Rehash Threshold: 120, Hash Seed: 0x0]
   [Age Threshold: 3]
  [Queue]
   [Dropped: 0]
편의를 위해서, 우리는 스스로 모든 데이터의 합계를 계산할 필요가 없고, 편리한 총계를 사용하면 된다.
위의 코드 세그먼트는 문자열을 다시 실행하는 데 16ms의 시간을 들여 약 120k 문자열을 보았습니다.
위의 특성은 방금 출시된 것으로 전면적으로 검토되지 않았을 수도 있다는 것을 의미한다.구체적인 데이터는 실제 응용에서 차이가 있을 수 있다. 특히 그 응용 프로그램에서 문자열이 여러 번 사용되고 전달되기 때문에 일부 문자열은 건너뛰거나 이미 해시코드가 있을 수 있다.
상기 사례에서 모든 문자열은 중복되고 메모리에서 4.5MB의 데이터를 제거합니다.
[table] 부분은 내부 추적표에 대한 통계 정보를 제시했고, [Queue]는 부하가 버려져서 중량을 줄이는 요청이 얼마나 많은지 열거했다. 이것도 비용 감소 메커니즘의 일부이다.
그렇다면 문자열의 무게는 문자열이 머무르는 것보다 어떤 차이가 있습니까?사실상 문자열의 중복과 주둔은 보기에 차이가 많지 않다. 임시 메커니즘을 제외하고 전체 문자열의 실례를 중용했다. 문자수 그룹뿐만 아니라.
JDK Enhancement Proposal 192의 창조자의 논쟁점은 개발자들이 주재하는 문자열을 어디에 놓는지 잘 모르거나 프레임워크에 숨겨져 있다는 점이다.내가 쓴 것처럼, 문자열 복사 (국가 이름처럼) 를 만났을 때, 너는 약간의 상식이 필요하다.문자열을 다시 하면 같은 JVM에 있는 응용 프로그램의 문자열 복사에도 도움이 된다. 마찬가지로 XML Schemas, urls,jar 이름 등 일반적으로 여러 번 나타나지 않는다고 생각하는 문자열을 포함한다.
문자열이 응용 프로그램 라인에 상주할 때, 쓰레기 회수가 비동기적으로 처리될 때, 문자열이 중복되어도 실행할 때의 소모가 증가하지 않습니다.이것도 우리가 왜 위의 코드에서Thread를 발견했는지 설명한다.sleep().만약 sleep가 없다면 GC에 너무 많은 압력을 증가시킬 것이다. 이렇게 하면 문자열이 중복되는 것은 전혀 일어나지 않을 것이다.그러나 이것은 예시 코드일 뿐이다.실제 응용 프로그램은 문자열을 다시 실행할 때 몇 밀리초의 시간을 사용합니다.

좋은 웹페이지 즐겨찾기