자바 String 대상(당신 은 정말 알 고 있 습 니까)
String 대상 은 자바 에서 가장 자주 사용 되 는 대상 중 하나 이기 때문에 자바 회사 도 String 대상 의 실현 을 최적화 시 켜 String 대상 의 성능 을 향상 시 키 고 있 습 니 다.아래 그림 을 보고 String 대상 의 최적화 과정 을 알 아 보 겠 습 니 다.
1.자바 6 및 이전 버 전에 서
String 대상 은 char 배열 을 패키지 하여 실현 한 대상 으로 주로 네 개의 구성원 변수 가 있 습 니 다.char 배열,오프셋 오프셋 오프셋,문자 수량 count,해시 값 hash.
String 대상 은 offset 과 count 두 속성 을 통 해 char[]배열 을 찾 아 문자열 을 가 져 옵 니 다.이렇게 하면 배열 대상 을 효율 적 이 고 신속하게 공유 하 는 동시에 메모리 공간 을 절약 할 수 있 지만 이런 방식 은 메모리 누 출 을 초래 할 수 있다.
2.자바 7 버 전부터 자바 8 버 전 까지
자바 7 버 전부터 자바 가 String 류 에 대해 약간의 변 화 를 주 었 다.String 클래스 에는 더 이상 offset 과 count 두 개의 변수 가 없습니다.이러한 장점 은 String 대상 이 차지 하 는 메모리 가 약간 적 고 String.substring 방법 도 char[]를 공유 하지 않 아 이 방법 을 사용 하면 발생 할 수 있 는 메모리 누 출 문 제 를 해결 하 는 것 이다.
3.자바 9 버 전부터
char[]배열 을 by te[]배열 로 바 꾸 는데 왜 이렇게 해 야 합 니까?우 리 는 char 가 두 바이트 라 는 것 을 알 고 있 습 니 다.만약 에 한 바이트 의 문 자 를 저장 하 는 데 낭비 가 있다 면 공간 을 절약 하기 위해 자바 회 사 는 하나의 바이트 의 byte 로 문자열 을 저장 합 니 다.이렇게 한 바이트 의 문 자 를 저장 하면 낭 비 를 피 할 수 있다.
자바 9 에서 새로운 속성 coder 를 유 지 했 습 니 다.인 코딩 형식의 표지 입 니 다.문자열 의 길 이 를 계산 하거나 index Of()함 수 를 호출 할 때 이 필드 에 따라 문자열 의 길 이 를 어떻게 계산 하 는 지 판단 해 야 합 니 다.coder 속성 은 기본적으로 0 과 1 두 개의 값 이 있 고 0 은 Latin-1(단일 바이트 인 코딩)을 대표 하 며 1 은 UTF-16 인 코딩 을 대표 합 니 다.String 이 문자열 에 Latin-1 만 포함 되 어 있다 고 판단 하면 coder 속성 값 은 0 이 고 그렇지 않 으 면 1 입 니 다.
String 대상 생 성 방식
1.문자열 상수 로
String str="pingtouge"형식 으로 문자열 을 만 들 때 JVM 은 문자열 상수 탱크 에서 대상 이 존재 하 는 지 확인 하고 존재 하면 대상 의 참조 주 소 를 되 돌려 줍 니 다.존재 하지 않 으 면 문자열 상수 탱크 에 이 문자열 쌍 을 만 들 고 인용 을 되 돌려 줍 니 다.이런 방식 으로 만 든 장점 은 같은 값 의 문자열 이 중복 되 는 것 을 피하 고 메모 리 를 절약 하 는 것 이다
2.String()구조 함수 의 방식
String str=new String("pingtouge")형식 으로 문자열 대상 을 만 드 는 과정 이 복잡 합 니 다.두 단계 로 나 뉘 어 있 습 니 다.먼저 컴 파일 할 때 문자열 pingtouge 는 상수 구조 에 추가 되 고 클래스 로 딩 할 때 상수 풀 에서 이 문자열 을 만 듭 니 다.그 다음 에 new()를 호출 할 때 JVM 은 String 의 구조 함 수 를 호출 하고 상수 탱크 의 pingtouge 문자열 을 참조 합 니 다.
메모리 에 String 대상 을 만 들 고 더미 에 있 는 참조 주 소 를 되 돌려 줍 니 다.
String 대상 의 두 가지 생 성 방식 을 알 게 되 었 습 니 다.다음 코드 를 분석 하고 이 두 가지 방식 에 대한 이 해 를 강화 하 겠 습 니 다.아래 코드 영화 에서 str 는 str 1 과 같 습 니까?
String str = "pingtouge";
String str1 = new String("pingtouge");
system.out.println(str==str1)
이 몇 줄 의 코드 를 하나씩 분석 해 보 겠 습 니 다.먼저 String str="pingtouge"부터 문자열 상수 방식 으로 문자열 대상 을 만 들 었 습 니 다.pingtouge 문자열 대상 을 만 들 때 JVM 은 상수 탱크 에 가서 이 문자열 이 존재 하 는 지 찾 습 니 다.여기 서 답 안 은 없 을 것 입 니 다.따라서 JVM 은 상수 탱크 에 이 문자열 대상 을 만 들 고 대상 의 주소 참조 로 돌아 갑 니 다.따라서 str 는 pingtouge 문자열 대상 이 상수 탱크 에 있 는 주소 참조 입 니 다.그 다음 에 String str 1=new String("pingtouge")코드 입 니 다.여 기 는 구조 함수 방식 으로 문자열 대상 을 만 듭 니 다.구조 함수 방식 으로 문자열 대상 을 만 드 는 것 에 대한 이해 에 따라 str 1 은 쌓 여 있 는 pingtouge 문자열 의 참조 주 소 를 얻 을 수 있 습 니 다.str 는 pingtouge 문자열 대상 이 상수 탱크 에 있 는 주 소 를 참조 하 는 것 을 가리 키 기 때문에 str 1 은 더미 에 있 는 pingtouge 문자열 의 참조 주 소 를 가리 키 기 때문에 str 는 str 1 과 같 지 않 을 것 입 니 다.
String 대상 의 불변성
우리 가 String 대상 을 알 게 된 순간 부터 String 대상 은 변 할 수 없다 는 것 을 모두 가 알 고 있 을 것 이 라 고 생각 합 니 다.그럼 얘 가 변 하지 않 는 건 어떻게 하 는 거 예요?자바 가 이렇게 하면 어떤 좋 은 점 을 가 져 올 수 있 습 니까?우리 함께 간단하게 토론 해 보 자.먼저 String 대상 의 소스 코드 를 살 펴 보 자.
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
}
이 소스 코드 에서 알 수 있 듯 이 String 류 는 final 수식 자 를 사 용 했 습 니 다.우 리 는 하나의 클래스 가 final 에 의 해 수식 되 었 을 때 이 클래스 가 계승 되 지 못 한 다 는 것 을 알 기 때문에 String 류 는 계승 되 지 못 합 니 다.String 의 변 함 없 는 첫 번 째 포인트 입 니 다.다시 아래 를 보면 문자열 을 저장 하 는 char value[]배열 은 private 와 final 에 의 해 수식 되 었 습 니 다.final 의 기본 데이터 형식 에 대한 변 수 는 초기 화 된 후에 변경 할 수 없다 는 것 을 알 고 있 습 니 다.이것 은 String 가 변 할 수 없 는 두 번 째 점 이다.
자바 회 사 는 왜 String 을 가 변 적 이지 않 게 설정 합 니까?주로 다음 과 같은 세 가지 측면 에서 고려 합 니 다.
문자열 은 우리 가 자주 사용 하 는 자바 형식 중 하나 이기 때문에 문자열 에 대한 조작 도 피 할 수 없습니다.문자열 을 조작 하 는 과정 에서 잘못 사용 하면 성능 이 천차만별 입 니 다.그렇다면 문자열 을 조작 하 는 과정 에서 우리 가 주의해 야 할 부분 은 무엇 입 니까?
우아 한 맞 춤 문자열
문자열 의 맞 춤 법 은 문자열 작업 에 가장 자주 사용 되 는 동작 중 하나 입 니 다.String 대상 의 불변성 을 알 고 있 기 때문에 우 리 는 맞 춤 법 을 만 들 때 가능 한 한 적 게+문자열 맞 춤 법 을 사용 하거나 잠재의식 적 으로+문자열 맞 춤 법 을 사용 할 수 없다 고 생각 합 니 다.+문자열 맞 춤 법 을 사용 하면 많은 쓸모없는 대상 이 생 길 수 있다 고 생각 합 니 다.사실 이 정말 그렇습니까?우리 실험 을 하나 하 자.우 리 는 아래 문자열 을 연결 하기 위해+를 사용 합 니 다.
String str8 = "ping" +"tou"+"ge";
이 코드 가 몇 개의 대상 을 만 들 수 있 는 지 분석 해 볼 까요?우리 가 이해 하 는 뜻 에 따라 분석 하면 먼저 ping 대상 을 만 들 고 pingtou 대상 을 만 들 고 마지막 에 pingtouge 대상 을 만 들 며 모두 세 개의 대상 을 만 들 었 습 니 다.정말 그런 가요?사실은 그렇지 않 습 니 다.자바 회 사 는 우리 프로그래머 가 잘못 할 까 봐 컴 파일 러 를 최적화 시 켰 습 니 다.위의 이 문자열 의 조합 은 우리 의 컴 파일 러 에 의 해 최적화 되 고 String str 8='pingtouge'로 최적화 될 것 입 니 다.대상상수 문자열 의 연결 을 최적화 하 는 것 을 제외 하고+번호 동적 연결 문자열 을 사용 하 는 데 있어 컴 파일 러 도 해당 하 는 최적화 를 하여 String 의 성능 을 향상 시 켰 다.예 를 들 어 다음 코드 와 같다.
String str = "pingtouge";
for(int i=0; i<1000; i++) {
str = str + i;
}
컴 파 일 러 가 이렇게 최적화 해 줄 거 예요.
String str = "pingtouge";
for(int i=0; i<1000; i++) {
str = (new StringBuilder(String.valueOf(str))).append(i).toString();
}
이 를 통 해 알 수 있 듯 이 자바 회 사 는 이 부분 에 대해 많은 최적화 를 했 고 프로그래머 가 부주의 로 인해 String 의 성능 이 급 격 히 떨 어 지 는 것 을 방지 했다.비록 자바 회 사 는 컴 파일 러 라 는 부분 에 해당 하 는 최적화 를 했 지만 우 리 는 자바 회사 의 최적화 부족 한 점 을 알 수 있다.동적 으로 문자열 을 연결 할 때 StringBuilder 를 사용 하여 문자열 을 연결 했다.그러나 순환 할 때마다 새로운 StringBuilder 인 스 턴 스 를 생 성하 고 시스템 의 성능 도 떨 어 집 니 다.그래서 우 리 는 문자열 연결 을 할 때 코드 차원 에서 최적화 해 야 합 니 다.동적 연결 문자열 을 사용 할 때 스 레 드 안전 과 관련 되 지 않 은 상황 에서 우 리 는 StringBuilder 를 사용 하여 연결 하여 시스템 성능 을 향상 시 켜 야 합 니 다.스 레 드 안전 과 관련 되면 StringBuffer 를 사용 하여 문자열 연결 을 합 니 다.
intern()방법 교묘 하 게 사용 하기
* <p>
* When the intern method is invoked, if the pool already contains a
* string equal to this {@code String} object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {@code String} object is added to the
* pool and a reference to this {@code String} object is returned.
* <p>
public native String intern();
이것 은 intern()함수 의 공식 주석 설명 입 니 다.아마도 intern 함 수 는 상수 탱크 의 한 문자열 을 되 돌려 주 는 데 사 용 될 것 입 니 다.상수 탱크 에 이 문자열 이 존재 한다 면 상수 탱크 에 있 는 대상 의 인용 을 직접 되 돌려 줍 니 다.그렇지 않 으 면 상수 탱크 에 이 대상 을 넣 고 인용 을 되 돌려 줍 니 다.한 트 위 터 엔 지 니 어 는 QCon 글로벌 소프트웨어 개발 대회 에서 String 대상 에 대한 최적화 사례 를 공유 했다.그들 은 String.intern()방법 을 이용 하여 이전 20G 메모리 저장 소 를 수백 조 메모리 로 최적화 시 켰 다.이것 은 String.intern()의 위력 을 충분히 나 타 낼 수 있 습 니 다.예 를 들 어 String.intern()의 용법 을 간단하게 알 아 보 겠 습 니 다.
public static void main(String[] args) {
String str = new String("pingtouge");
String str1 = new String("pingtouge");
System.out.println(" intern() :"+(str==str1));
System.out.println(" intern() ,str:"+str);
System.out.println(" intern() ,str1:"+str1);
String str2= new String("pingtouge").intern();
String str3 = new String("pingtouge").intern();
System.out.println(" intern() :"+(str2==str3));
System.out.println(" intern() ,str2:"+str2);
System.out.println(" intern() ,str3:"+str3);
}
결과 에서 보 듯 이 String.intern()방법 을 사용 하지 않 았 을 때 같은 값 을 구성 한 문자열 대상 은 서로 다른 대상 의 참조 주 소 를 되 돌려 주 고 String.intern()방법 을 사용 한 후 같은 값 의 문자열 대상 을 구성 할 때 같은 대상 의 참조 주 소 를 되 돌려 줍 니 다.이것 은 우리 가 많은 공간 을 절약 하 는 데 도움 을 줄 수 있다.
String.intern()방법 은 좋 지만 우 리 는 장면 과 결합 하여 사용 해 야 합 니 다.함부로 사용 해 서 는 안 됩 니 다.상수 탱크 의 실현 은 하나의 Hash Table 과 유사 한 실현 방식 이기 때문에 Hash Table 에 저 장 된 데이터 가 클 수록 옮 겨 다 니 는 시간 복잡 도가 증가 합 니 다.데이터 가 너무 크 면 전체 문자열 상수 탱크 의 부담 이 증가 합 니 다.
유연 한 문자열 분할
문자열 의 분할 은 문자열 작업 에 자주 사용 되 는 작업 중 하나 입 니 다.문자열 의 분할 은 대부분 Split()방법 을 사용 합 니 다.Split()방법 은 대부분 정규 표현 식 을 사용 합 니 다.이러한 분할 방식 자체 에 문제 가 없 지만 정규 표현 식 의 성능 은 매우 불안정 합 니 다.부적 절 한 사용 은 역 추적 문 제 를 일 으 킬 수 있 습 니 다.CPU 가 높 아 지지 않 을 가능성 이 높다.다음 두 가지 상황 에서 Split()방법 은 정규 표현 식 을 사용 하지 않 습 니 다.
문장 에 부족 한 점 이 있 으 면,여러분 들 께 서 많이 지적 해 주시 고,함께 공부 하 며,함께 진보 해 주시 기 바 랍 니 다.
참고 자료
자바 성능 개선 실전 유 초
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.