머리말
Java 개발자 중에서 문자열의 높은 리소스 점유는 종종 뜨거운 주제입니다.
왜 높은 자원을 차지하는지 깊이 논의합시다.
Java에서는 문자열 객체가 불변이므로 일단 생성되면 더 이상 변경할 수 없습니다. 그래서 우리가 줄을 스플 라이스 할 때, 우리는 새로운 문자열을 만들고, 오래된 문자열은 쓰레기 수집기로 표시됩니다.
수백만 개의 문자열을 처리하면 쓰레기 수집기가 처리 할 수백만 개의 추가 문자열을 생성합니다.
대부분의 튜토리얼에서는 스플 라이스 스트링에 + 표지판을 사용하면 여러 문자열이 생겨 성능이 저하 될 수 있습니다. StringBuffer/StringBuilder를 스플 라이스에 사용하는 것이 좋습니다.
그러나 이것이 사실입니까?
이 기사는 JDK8에서 다음 실험을 수행했습니다.
public static void main (String [] args) {String result = ""; 결과 += "더 많은 데이터"; System.out.println (결과); }javap -c를 통해 소집하기 위해 :
코드 : 0 : aload_0 // 스택에 'this'를 누르십시오. 코드 : 0 : LDC #2 // 스택 2에 상수 #2를로드합니다. invokeVirtual #5 // 메소드를 호출하는 stringBuilder.append () // pop obj 참조 + 매개 변수 // 푸시 결과 (StringBuilder Ref) 14 : ldc #6 // 스택에서 "일부 더 많은 데이터"푸시 16 : invokevirtual #5 // stringbuilder.append // pop invokevirtual #7 // invoke buylder. 22 : store_1 // 스택에서 로컬 var 생성 (POP #6) 23 : getstatic #8 // 푸시 값 시스템. 아웃 : printstream 26 : aload_1 // #6 27 : invokevirtual #9 // 메소드 printstream.println () // 팝 + 매개 변수를 호출하십시오.
Java 컴파일러는 생성 된 바이트 코드를 최적화하고 자동으로 StringBuilder를 생성하며 Append 작업을 수행한다는 것을 알 수 있습니다.
최종 문자열의 하위 문자열은 컴파일 타임에 이미 알려져 있기 때문에 Java 컴파일러는이 경우 위의 최적화를 수행합니다. 이 최적화를 정적 문자열 연결 최적화라고하며 JDK5 이후에 활성화되었습니다.
JDK5 후에는 더 이상 StringBuilder를 수동으로 생성 할 필요가 없으며 + 부호를 통해 동일한 성능을 달성 할 수 있다는 것을 의미합니까?
역동적으로 스 플라이 싱 스트링을 시도해 봅시다 :
동적 스 플라이 싱 스트링은 런타임에만 알려진 하위 문자열을 나타냅니다. 예를 들어 루프에 문자열을 추가합니다.
public static void main (String [] args) {String result = ""; for (int i = 0; i <10; i ++) {result+= "일부 더 많은 데이터"; } system.out.println (결과); }또한 분해 :
코드 : 0 : aload_0 // 스택에 'this'를 누르십시오. 코드 : 0 : LDC #2 // 스택 2에 상수 #2를로드합니다. 2 : Store_1 // 스택에서 로컬 var 생성, 팝 #2 3 : iconst_0 // 값 0을 스택 4 : istore_2 // 로컬 var 5에 푸시하고 로컬 var 2를 스택으로 눌러 로컬 var 2를 눌렀습니다. ldc2_w #3 // Stack 10에 상수 10e6을 푸시하십시오. 10 : dcmpg // 스택 상단에 두 개의 복식 비교 // 두 번 팝 결과 : -1, 0 또는 1 11 : ifge 40 // 스택 상단의 값이 0보다 크거나 동일하다면 // 코드 40에서 명령에 대한 분기 또는 푸시 값 17 : dup on string on stpack on stpack on stpack on stpack on the Stringbual on the Strathbuilbuil on that on the Stringbuil on that on the uptruction to 0 to 0 (팝 40 // ifge 40 // ifge 40 //). StringBuilder 생성기 // 팝 객체 참조 21 : aload_1 // 로컬 var 1 (빈 문자열) // in a invokevirtual #7 // intokevirtual #7 // stringbuilder.append // pop obj ref + param. StringBuilder.append // pop obj ref + param, 푸시 결과 30 : invokevirtual #9 // stringbuilder.toString invoke stringbuilder.toString 참조 33 : Store_1 // Stack (pop)에서 로컬 var 생성 (pop) 34 : iinc 2, 1 // 1 37 : goto 5 // gettatic #10 // gettatic #10 // 43 : aload_1 // local var 1 (결과 문자열) 44 : invokevirtual #11 // 메소드 printstream.println () // 팝 팝 (개체 ref + 매개 변수) 47 : method에서 void를 반환합니다.
StringBuilder가 14 세에 새로 새로워졌지만 37 세, Goto 5. 루프 중에 최적화가 달성되지 않았으며 새로운 StringBuilders가 끊임없이 생성되었습니다.
위의 코드는 비슷합니다.
문자열 result = ""; for (int i = 0; i <10; i ++) {StringBuilder tmp = new StringBuilder (); tmp.append (결과); tmp.append ( "일부 더 데이터"); 결과 = tmp.tostring ();} system.out.println (결과);새로운 StringBuilders가 지속적으로 생성되고 Tostring을 통해 원래 StringBuilder는 더 이상 쓰레기로 참조되지 않으며 GC 비용도 증가합니다.
따라서 실제로 사용하면 문자열이 정적인지 동적인지 여부를 구별 할 수 없을 때 StringBuilder를 사용하십시오.
참조:
http://www.pellegrino.link/2015/08/22/string-concatenation-with-java-8.html
요약
위는이 기사의 전체 내용입니다. 이 기사의 내용에 모든 사람의 연구 나 작업에 대한 특정 참조 가치가 있기를 바랍니다. 궁금한 점이 있으면 의사 소통을 위해 메시지를 남길 수 있습니다. Wulin.com을 지원 해주셔서 감사합니다.