문제

String s = "";
for(i=0;i<....){
    s = some Assignment;
}

또는

for(i=0;i<..){
    String s = some Assignment;
}

다시는 루프 외부에서 's'를 사용할 필요가 없습니다.새 문자열이 매번 초기화되지 않기 때문에 첫 번째 옵션이 더 나을 수도 있습니다.그러나 두 번째는 변수의 범위가 루프 자체로 제한되는 결과를 낳습니다.

편집하다:Milhous의 답변에 대한 응답입니다.루프 내에서 문자열을 상수에 할당하는 것은 의미가 없습니다. 그렇지 않습니까?아니요, 여기서 '일부 할당'은 반복되는 목록에서 가져온 변경 값을 의미합니다.

또한 문제는 메모리 관리가 걱정되기 때문이 아닙니다.어느 것이 더 나은지 알고 싶습니다.

도움이 되었습니까?

해결책

제한된 범위가 가장 좋습니다

두 번째 옵션을 사용하세요.

for ( ... ) {
  String s = ...;
}

범위는 성능에 영향을 미치지 않습니다

각각에서 컴파일된 코드를 분해하면(JDK의 javap 도구), 두 경우 모두 루프가 정확히 동일한 JVM 명령어로 컴파일되는 것을 볼 수 있습니다.또한 브라이언 R.본디의 "옵션 #3"은 옵션 #1과 동일합니다.더 엄격한 범위를 사용할 때 스택에 추가되거나 제거되는 것은 없으며 두 경우 모두 스택에서 동일한 데이터가 사용됩니다.

조기 초기화 방지

두 경우의 유일한 차이점은 첫 번째 예에서는 변수가 s 불필요하게 초기화되었습니다.이는 변수 선언 위치와는 별개의 문제입니다.이는 두 개의 낭비된 명령을 추가합니다(문자열 상수를 로드하고 이를 스택 프레임 슬롯에 저장하기 위해).좋은 정적 분석 도구는 사용자가 할당한 값을 읽지 않는다고 경고합니다. s, 좋은 JIT 컴파일러는 아마도 런타임에 이를 제거할 것입니다.

빈 선언을 사용하여 이 문제를 간단히 해결할 수 있습니다(예: String s;) 그러나 이는 나쁜 습관으로 간주되며 아래에서 설명하는 또 다른 부작용이 있습니다.

종종 다음과 같은 가짜 값이 사용됩니다. null 초기화되지 않고 변수를 읽는 컴파일러 오류를 간단히 처리하기 위해 변수에 할당됩니다.이 오류는 변수 범위가 너무 크고 유효한 값을 받기 위해 필요하기 전에 변수가 선언되고 있다는 힌트로 간주될 수 있습니다.빈 선언으로 인해 모든 코드 경로를 고려해야 합니다.가짜 값을 할당하여 이 귀중한 경고를 무시하지 마십시오.

스택 슬롯 절약

언급한 대로 JVM 명령은 두 경우 모두 동일하지만 JVM 수준에서 가능한 가장 제한된 범위를 사용하는 것이 가장 좋은 미묘한 부작용이 있습니다.이는 해당 메소드의 "로컬 변수 테이블"에 표시됩니다.불필요하게 큰 범위에 변수가 선언된 여러 루프가 있는 경우 어떻게 되는지 생각해 보세요.

void x(String[] strings, Integer[] integers) {
  String s;
  for (int i = 0; i < strings.length; ++i) {
    s = strings[0];
    ...
  }
  Integer n;
  for (int i = 0; i < integers.length; ++i) {
    n = integers[i];
    ...
  }
}

변수 s 그리고 n 각각의 루프 내에서 선언할 수 있지만 그렇지 않기 때문에 컴파일러는 스택 프레임에서 두 개의 "슬롯"을 사용합니다.루프 내에서 선언된 경우 컴파일러는 동일한 슬롯을 재사용하여 스택 프레임을 더 작게 만들 수 있습니다.

정말로 중요한 것

그러나 이러한 문제의 대부분은 중요하지 않습니다.좋은 JIT 컴파일러는 낭비적으로 할당하는 초기 값을 읽을 수 없다는 것을 확인하고 할당을 최적화합니다.여기 저기에 슬롯을 저장해도 애플리케이션이 성공하거나 중단되지 않습니다.

중요한 것은 코드를 읽기 쉽고 유지 관리하기 쉽게 만드는 것입니다. 그런 점에서는 제한된 범위를 사용하는 것이 확실히 더 좋습니다.변수의 범위가 작을수록 변수 사용 방법과 코드 변경 사항이 미치는 영향을 더 쉽게 이해할 수 있습니다.

다른 팁

~ 안에 이론, 루프 내부에서 문자열을 선언하는 것은 리소스 낭비입니다.~ 안에 관행, 그러나 제시된 두 스니펫은 모두 동일한 코드(루프 외부 선언)로 컴파일됩니다.

따라서 컴파일러가 어느 정도 최적화를 수행하더라도 차이는 없습니다.

일반적으로 's' 변수의 범위는 루프로 제한되기 때문에 두 번째 것을 선택합니다.이익:

  • 이는 나중에 함수 어딘가에서 's'가 다시 사용되는 것에 대해 걱정할 필요가 없기 때문에 프로그래머에게 더 좋습니다.
  • 이는 변수의 범위가 더 작고 잠재적으로 더 많은 분석과 최적화를 수행할 수 있기 때문에 컴파일러에 더 좋습니다.
  • 이는 나중에 사용되지 않는 's' 변수가 루프 외부에서 선언되는 이유를 궁금해하지 않기 때문에 미래의 독자에게 더 좋습니다.

for 루프의 속도를 높이려면 조건에 대한 반복 조회가 필요하지 않도록 카운터 옆에 max 변수를 선언하는 것이 좋습니다.

대신에

for (int i = 0; i < array.length; i++) {
  Object next = array[i];
}

나는 선호한다

for (int i = 0, max = array.lenth; i < max; i++) {
  Object next = array[i];
}

고려해야 할 다른 사항은 이미 언급되었으므로 2센트만 지불하세요(Ericksons 게시물 참조).

안녕하세요, GHad

@에 약간을 추가하려면에스테반 아라야의 답변, 둘 다 루프를 통해 매번 새 문자열을 생성해야 합니다(의 반환 값으로). some Assignment 표현).해당 문자열은 어느 쪽이든 가비지 수집되어야 합니다.

나는 이것이 오래된 질문이라는 것을 알고 있지만 조금 추가하고 싶다고 생각했습니다. 약간 관련된.

Java 소스 코드를 탐색하는 동안 String.contentEquals(아래에 복제됨)와 같은 일부 메소드가 단순히 클래스 변수의 복사본인 중복된 로컬 변수를 만드는 것을 발견했습니다.나는 어딘가에 로컬 변수에 액세스하는 것이 클래스 변수에 액세스하는 것보다 빠르다는 것을 암시하는 의견이 있다고 생각합니다.

이 경우 "v1"과 "v2"는 불필요한 것처럼 보이며 코드를 단순화하기 위해 제거할 수 있지만 성능 향상을 위해 추가되었습니다.

public boolean contentEquals(StringBuffer sb) {
    synchronized(sb) {
        if (count != sb.length())
            return false;
        char v1[] = value;
        char v2[] = sb.getValue();
        int i = offset;
        int j = 0;
        int n = count;
        while (n-- != 0) {
            if (v1[i++] != v2[j++])
                return false;
        }
    }
    return true;
}

제가 보기에는 문제에 대한 더 자세한 설명이 필요한 것 같습니다.

그만큼

s = some Assignment;

이것이 어떤 종류의 임무인지는 명시되어 있지 않습니다.과제라면

s = "" + i + "";

그런 다음 새로운 찌르기를 할당해야 합니다.

하지만 그렇다면

s = some Constant;

s는 단지 상수 메모리 위치를 가리킬 뿐이므로 첫 번째 버전이 메모리 효율성이 더 높습니다.

해석된 언어 IMHO에 대한 for 루프의 많은 최적화에 대해 걱정하는 것은 조금 어리석은 것 같습니다.

여러 스레드(50개 이상)를 사용할 때 이것이 프로세스를 올바르게 닫을 수 없는 고스트 스레드 문제를 처리하는 매우 효과적인 방법이라는 것을 알았습니다....내가 틀렸다면 이유를 알려주십시오. 내가 틀렸다:

Process one;
BufferedInputStream two;
try{
one = Runtime.getRuntime().exec(command);
two = new BufferedInputStream(one.getInputStream());
}
}catch(e){
e.printstacktrace
}
finally{
//null to ensure they are erased
one = null;
two = null;
//nudge the gc
System.gc();
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top