jdk-9 String Concatenation에 얼마나 많은 노력을 기울 였는지 놀라실 것입니다. 첫 번째 javac은 StringBuilder#append
에 대한 호출 대신 invokedynamic
을 내 보냅니다. invokedynamic은 CallSite
을 반환하고 MethodHandle (실제로는 일련의 MethodHandles)을 포함합니다.
따라서 문자열 결합에 대해 실제로 수행 된 결정이 런타임으로 이동됩니다. 단점은 문자열의 연결을 처음으로 느리게하는 것입니다 (같은 유형의 인수에 대해).
이 그럼 당신은 문자열을 연결 때 선택할 수있는 전략의 시리즈가 있습니다 (디폴트에게 하나의 매개 변수 java.lang.invoke.stringConcat
를 통해를 대체 할 수 있습니다) :
private enum Strategy {
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder}.
*/
BC_SB,
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder};
* but trying to estimate the required storage.
*/
BC_SB_SIZED,
/**
* Bytecode generator, calling into {@link java.lang.StringBuilder};
* but computing the required storage exactly.
*/
BC_SB_SIZED_EXACT,
/**
* MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
* This strategy also tries to estimate the required storage.
*/
MH_SB_SIZED,
/**
* MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
* This strategy also estimate the required storage exactly.
*/
MH_SB_SIZED_EXACT,
/**
* MethodHandle-based generator, that constructs its own byte[] array from
* the arguments. It computes the required storage exactly.
*/
MH_INLINE_SIZED_EXACT
}
기본 전략은 다음과 같습니다 MH_INLINE_SIZED_EXACT
짐승이다!
그것은 문자열을 구축하기 위해 패키지 개인 생성자를 사용 (가장 빠른 인) :
/*
* Package private constructor which shares value array for speed.
*/
String(byte[] value, byte coder) {
this.value = value;
this.coder = coder;
}
먼저 그렇게 필터라는 만듭니다이 전략; 이들은 기본적으로 들어오는 매개 변수를 String 값으로 변환하는 메서드 핸들입니다. 하나 예상 할 수 있듯이,이 MethodHandles 대부분의 경우는 MethodHandle을 생산에 호출하는 것을 Stringifiers
라는 클래스에 저장됩니다
String.valueOf(YourInstance)
을 그래서 당신은 당신이 연결할 할 3 개체가있는 경우 위임합니다 3 MethodHandles가있을 것입니다 String.valueOf(YourObject)
으로 변경하면 효과적으로 개체를 문자열로 변형 한 것입니다. 이 수업에는 여전히 이해할 수없는 개조가 있습니다. 필요에 따라 StringifierMost
(문자열 만 참조로 변환, 부동 및 복식으로 변환) 및 StringifierAny
클래스가 별도로 있어야합니다.
MH_INLINE_SIZED_EXACT
은 바이트 배열이 정확한 크기로 계산된다고 말합니다. 그것을 계산할 방법이 있습니다.
이 방법은 StringConcatHelper#mixLen
의 입력 매개 변수 (참조/부동/이중)의 문자열 버전을 사용하는 방법을 통해 수행됩니다. 이 시점에서 최종 문자열의 크기를 알 수 있습니다. 글쎄, 우리는 실제로 그것을 모른다., 우리는 그것을 계산할 MethodHandle이있다.
여기서 언급 할만한 가치가있는 String jdk-9의 또 다른 변경 사항이 있습니다. coder
필드가 추가되었습니다. 이것은, String의 사이즈/동일성/charAt를 계산하기 위해서 필요합니다. 크기에 필요하기 때문에이를 계산해야합니다. 이것은 StringConcatHelper#mixCoder
을 통해 이루어집니다.
UR 배열을 생성하는 MethodHandle 위임하는이 시점에서 안전 : 가
@ForceInline
private static byte[] newArray(int length, byte coder) {
return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, length << coder);
}
어떻게 각 요소
을 추가됩니다 를? 방법을 통해
StringConcatHelper#prepend
.
이제는 바이트를 사용하는 String의 생성자를 호출하는 데 필요한 모든 세부 사항 만 필요합니다.
이러한 모든 작업 (및 많은 다른 내가 편의상 생략 한)이 첨부 된이 실제로 발생했을 때 호출 될 MethodHandle 발광 통해 처리됩니다.
표현식을 연결할 때 재진입을 조심하십시오. – SLaks
마지막으로, 꽤 바보 같아서'StringBuilder'가 반복해서 재 할당되도록했습니다. 그러나 이것은 오라클의 JDK에만 해당되며 결과로 생성되는 바이트 코드를 살펴 보았으므로 JVM이 수행 할 수있는 최적화를 고려하지 않았습니다. 내 규칙은 다음과 같습니다. 물론 99.999 %는 신경 쓰지 않아도됩니다. .001 %를 돌보는 곳에서는 총 결과를 처리 할만큼 충분히 큰 할당 된 명시 적'StringBuilder'를 사용하십시오. –
한 줄보다 더 많은 문자열 조작을하지 않는 한, T.J .: 99.999 %의 시간에는 아무런 차이가 없을 것입니다. JVM은 실제로 모든 메모리를 로컬 스레드로 할당합니다 (다른 스레드와 공유해야 할 때까지). 따라서 스레드 로컬은 아무런 효과가 없을 것입니다. – markspace