program tip

65 개 요소로 구성된 배열을 선언하는 것보다 1000 배 빠른 64 개 요소로 여러 배열을 선언합니다.

radiobox 2020. 9. 4. 07:07
반응형

65 개 요소로 구성된 배열을 선언하는 것보다 1000 배 빠른 64 개 요소로 여러 배열을 선언합니다.


최근에 64 개 요소를 포함하는 배열을 선언하는 것이 65 개 요소로 동일한 유형의 배열을 선언하는 것보다 훨씬 빠릅니다 (> 1000 배).

이것을 테스트하는 데 사용한 코드는 다음과 같습니다.

public class Tests{
    public static void main(String args[]){
        double start = System.nanoTime();
        int job = 100000000;//100 million
        for(int i = 0; i < job; i++){
            double[] test = new double[64];
        }
        double end = System.nanoTime();
        System.out.println("Total runtime = " + (end-start)/1000000 + " ms");
    }
}

이 작업은 약 6ms에 실행되며 교체 new double[64]하는 new double[65]경우 약 7 초가 걸립니다. 이 문제는 작업이 점점 더 많은 스레드에 분산되면 기하 급수적으로 더 심각해집니다.

이 문제는 또한 다음과 같은 배열의 다른 유형의 발생 int[65]또는 String[65]. 이 문제는 큰 문자열 String test = "many characters";에서는 발생하지 않지만 다음으로 변경되면 발생하기 시작합니다.String test = i + "";

왜 이것이 사실인지 그리고이 문제를 피할 수 있는지 궁금합니다.


Java VM의 JIT 컴파일러가 수행 한 최적화 로 인해 발생하는 동작을 관찰하고 있습니다 . 이 동작은 최대 64 개 요소의 스칼라 배열로 트리거 될 수 있으며 64보다 큰 배열에서는 트리거되지 않습니다.

자세히 살펴보기 전에 루프의 본문을 자세히 살펴 보겠습니다.

double[] test = new double[64];

몸은 효과가 없습니다 (관찰 가능한 행동) . 즉,이 명령문의 실행 여부에 관계없이 프로그램 실행 외부에서 아무런 차이가 없습니다. 전체 루프에 대해서도 마찬가지입니다. 따라서 코드 옵티마이 저가 루프를 동일한 기능과 다른 타이밍 동작을 가진 무언가 (또는 아무것도)변환 할 수 있습니다.

벤치 마크의 경우 최소한 다음 두 가지 지침을 준수해야합니다. 그렇게했다면 그 차이는 훨씬 더 작았을 것입니다.

  • 벤치 마크를 여러 번 실행하여 JIT 컴파일러 (및 최적화 프로그램)를 워밍업합니다.
  • 모든 표현의 결과를 사용하고 벤치 마크 끝에 인쇄하십시오.

이제 자세히 살펴 보겠습니다. 당연히 64 요소보다 크지 않은 스칼라 배열에 대해 트리거되는 최적화가 있습니다. 최적화는 탈출 분석의 일부입니다 . 작은 개체와 작은 배열을 힙에 할당하는 대신 스택에 배치하거나 완전히 최적화하는 것이 좋습니다. 2005 년에 작성된 Brian Goetz의 다음 기사에서 이에 대한 정보를 찾을 수 있습니다.

명령 줄 옵션을 사용하여 최적화를 비활성화 할 수 있습니다 -XX:-DoEscapeAnalysis. 스칼라 배열의 매직 값 64는 명령 줄에서도 변경할 수 있습니다. 다음과 같이 프로그램을 실행하면 64 개와 65 개 요소가있는 배열간에 차이가 없습니다.

java -XX:EliminateAllocationArraySizeLimit=65 Tests

하지만 이러한 명령 줄 옵션을 사용하지 않는 것이 좋습니다. 나는 그것이 현실적인 응용 프로그램에 큰 차이를 만들지 의심합니다. 필자는 일부 의사 벤치 마크의 결과를 기반으로하지 않고 필요성을 절대적으로 확신 할 경우에만 사용합니다.


개체의 크기에 따라 차이가있을 수있는 방법에는 여러 가지가 있습니다.

nosid가 언급했듯이 JITC는 스택에 작은 "로컬"개체를 할당 할 수 있으며 "작은"배열의 크기 컷오프는 64 요소 일 수 있습니다.

스택에 할당하는 것이 힙에 할당하는 것보다 훨씬 빠르며, 더 나아가서 스택은 가비지 수집이 필요하지 않으므로 GC 오버 헤드가 크게 감소합니다. (이 테스트 케이스의 경우 GC 오버 헤드는 총 실행 시간의 80-90 % 일 가능성이 높습니다.)

또한 값이 스택 할당되면 JITC는 "데드 코드 제거"를 수행하고 그 결과가 new어디에도 사용되지 않는지 확인하고 손실 될 부작용이 없는지 확인한 후 전체 new작업을 제거 할 수 있습니다 . 그런 다음 (현재 비어있는) 루프 자체가 있습니다.

JITC가 스택 할당을 수행하지 않더라도 특정 크기보다 작은 객체가 더 큰 객체와 다르게 (예 : 다른 "공간"에서) 힙에 할당되는 것이 전적으로 가능합니다. (일반적으로 이것은 그렇게 극적인 타이밍 차이를 생성하지 않습니다.)

참고 URL : https://stackoverflow.com/questions/18810505/declaring-multiple-arrays-with-64-elements-1000-times-faster-than-declaring-arra

반응형