[java] 문자열에“”를 추가하면 왜 메모리가 절약됩니까?

많은 데이터가있는 변수를 사용했습니다 String data. 이 문자열의 작은 부분을 다음과 같은 방식으로 사용하고 싶었습니다.

this.smallpart = data.substring(12,18);

몇 시간의 디버깅 (메모리 시각화 도구 사용) 후에는 객체 필드 에 하위 문자열 만 포함되어 있지만 객체 필드의 smallpart모든 데이터를 기억 한다는 것을 알았습니다 data.

코드를 다음과 같이 변경했을 때 :

this.smallpart = data.substring(12,18)+""; 

.. 문제가 해결되었습니다! 이제 내 응용 프로그램은 메모리를 거의 사용하지 않습니다!

어떻게 가능합니까? 누구든지 이것을 설명 할 수 있습니까? 작은 부분은 계속 데이터를 참조한다고 생각하지만 왜 그럴까요?

업데이트 :
큰 문자열을 지우려면 어떻게해야합니까? data = new String (data.substring (0,100))이 작동합니까?



답변

다음을 수행하십시오.

data.substring(x, y) + ""

새로운 (더 작은) String 객체를 만들고 substring ()으로 만든 String에 대한 참조를 버려서 가비지 수집을 가능하게합니다.

알아야 할 중요한 점 substring()기존 문자열 또는 원래 문자열의 기본이되는 문자 배열에 창 을 제공 한다는 것입니다 . 따라서 원래 문자열과 동일한 메모리를 사용합니다. 이것은 어떤 상황에서는 유리할 수 있지만, 부분 문자열을 가져 와서 원래 문자열을 처리하려는 경우 문제가됩니다 (발견 한대로).

자세한 정보는 JDK 문자열 소스 의 substring () 메소드 를보십시오.

편집 : 당신의 메모리 사용량을 줄입니다 문자열에서 새로운 문자열을 구성, 당신의 보충 질문에 대한 답을 제공하는 원래의 문자열에 당신에게 참조를 빈.

참고 (2013 년 1 월). 위의 동작은 Java 7u6에서 변경 되었습니다 . 플라이급 패턴은 더 이상 사용되지 않으며 substring()예상대로 작동합니다.


답변

의 출처를 보면 다음을 substring(int, int)반환 함을 알 수 있습니다.

new String(offset + beginIndex, endIndex - beginIndex, value);

value원본은 어디에 있습니까 char[]? 따라서 새로운 String을 얻지 만 기본 이 동일char[] 합니다.

당신이 할 때 data.substring() + "", 당신은 새로운 기초를 가진 새로운 문자열을 얻는다 char[].

실제로 유스 케이스는 String(String)생성자 를 사용해야하는 유일한 상황입니다 .

String tiny = new String(huge.substring(12,18));


답변

을 사용할 때 substring실제로 새 문자열을 만들지는 않습니다. 여전히 오프셋과 크기 제한이있는 원래 문자열을 참조합니다.

따라서 원래 문자열을 수집하려면 new String, 또는 사용하여 새 문자열을 만들어야합니다 .


답변

작은 부분은 계속 데이터를 참조한다고 생각하지만 왜 그럴까요?

Java 문자열은 char 배열, 시작 오프셋 및 길이 (및 캐시 된 hashCode)로 구성됩니다. 일부 String 작업 substring()은 원본의 char 배열을 공유하고 단순히 오프셋 및 / 또는 길이 필드가 다른 새 String 객체를 만드는 것과 같습니다 . String의 char 배열은 일단 생성되면 수정되지 않기 때문에 작동합니다.

여러 하위 문자열이 겹치는 부분을 복제하지 않고 동일한 기본 문자열을 참조 할 때 메모리를 절약 할 수 있습니다. 알다시피, 어떤 상황에서는 더 이상 필요하지 않은 데이터를 가비지 수집하지 못하게 할 수 있습니다.

이것을 고치는 “올바른”방법은 new String(String)생성자입니다.

this.smallpart = new String(data.substring(12,18));

BTW의 전반적인 최상의 솔루션은 처음에는 매우 큰 문자열을 사용하지 않고 한 번에 몇 KB 씩 작은 청크로 입력을 처리하는 것을 피하는 것입니다.


답변

Java 문자열에서 문자열은 변경 불가능한 개체이며 일단 문자열이 생성되면 가비지 콜렉터가 정리할 때까지 메모리에 남아 있습니다 (이 정리는 당연한 것으로 간주되지 않습니다).

부분 문자열 메소드를 호출하면 Java는 완전히 새로운 문자열을 만들지 않고 원래 문자열 안에 다양한 문자를 저장합니다.

따라서이 코드로 새 문자열을 만들 때 :

this.smallpart = data.substring(12, 18) + ""; 

빈 문자열로 결과를 연결할 때 실제로 새 문자열을 만들었습니다. 그 이유입니다.


답변

1997 년jwz기록한 대로 :

거대한 문자열이있는 경우 하위 문자열 ()을 꺼내고 하위 문자열을 잡고 더 긴 문자열이 가비지가되도록 허용하십시오 (즉, 하위 문자열의 수명이 길어짐). 거대한 문자열의 기본 바이트는 절대 가지 않습니다. 떨어져.


답변

요약하면 소수의 큰 문자열에서 많은 하위 문자열을 만들면 다음을 사용하십시오.

   String subtring = string.substring(5,23)

큰 문자열을 저장하기 위해 공간 만 사용하기 때문에 큰 문자열의 손실에서 소수의 작은 문자열을 추출하는 경우

   String substring = new String(string.substring(5,23));

더 이상 필요하지 않을 때 큰 문자열을 회수 할 수 있으므로 메모리 사용을 줄입니다.

전화 new String한다는 것은 원래 문자열에 대한 참조가 아니라 실제로 새로운 문자열을 받고 있음을 알려주는 유용한 정보입니다.