System.arraycopy가 Java에서 기본 제공되는 이유는 무엇입니까?


84

Java 소스에서 System.arraycopy가 기본 메서드라는 사실에 놀랐습니다.

물론 그 이유는 더 빠르기 때문입니다. 그러나 코드가 더 빠르게 사용할 수있는 기본 트릭은 무엇입니까?

원래 배열을 반복하고 각 포인터를 새 배열에 복사하지 않는 이유는 무엇입니까? 확실히 느리고 성가신 일이 아닙니다.

답변:


82

네이티브 코드에서는 n 개의 고유 한 복사 작업 과는 반대로 단일 memcpy/ 로 수행 할 수 있습니다 . 성능의 차이는 상당합니다.memmove


@Peter, 네이티브 코드 내에서 Java 메모리 모델을 사용할 수 있습니까? (나는 네이티브 말라 키를 할 이유가 없었습니다)
James B

8
실제로의 일부 하위 사례 만 /를 arraycopy사용하여 구현할 수 있습니다 . 다른 것들은 복사 된 각 요소에 대한 런타임 유형 검사를 필요로합니다. memcpymemmove
Stephen C

1
@Stephen C, 흥미 롭습니다-왜 그럴까요?
Péter Török

3
@ Péter Török- Object[]채워진 String개체에서 String[]. java.sun.com/javase/6/docs/api/java/lang/…의
Stephen C

3
Peter, Object [] 및 byte [] + char []는 가장 자주 복사되며 명시적인 유형 검사가 필요하지 않습니다. 컴파일러는 필요한 경우가 아니면 확인할 수 없을만큼 똑똑하며 사실상 그렇지 않은 경우의 99.9 %입니다. 재미있는 부분은 작은 크기의 복사본 (캐시 라인보다 작음)이 상당히 우세하므로 작은 크기의 경우 "memcpy"가 빠르다는 것이 정말 중요합니다.
bestsss

16

Java로 작성할 수 없습니다. 네이티브 코드는 Object 배열과 기본 배열 간의 차이를 무시하거나 제거 할 수 있습니다. 자바는 최소한 효율적으로 할 수 없습니다.

그리고 중첩 배열에 필요한 의미 체계 때문에 단일으로 작성할 수 없습니다memcpy() .


5
좋아, memmove그럼. 이 질문의 맥락에서 큰 차이가 있다고 생각하지 않지만.
Péter Török

memmove ()도 아닙니다. 다른 답변에 대한 @Stephen C의 의견을 참조하십시오.
Marquis of Lorne 2011

그것은 내 자신의 대답이기 때문에 이미 봤습니다 ;-) 어쨌든 감사합니다.
Péter Török 2011

1
겹치는 @Geek 배열. 소스 및 대상 배열과 동일하고 오프셋 만 다른 경우 동작이 신중하게 지정되고 memcpy ()가 준수하지 않습니다.
Marquis of Lorne

1
그것은 할 수없는 자바로 작성? Object의 하위 클래스를 처리하기 위해 하나의 제네릭 메서드를 작성한 다음 각 기본 유형에 대해 하나씩 작성할 수 없습니까?
Michael Dorst

10

물론 구현에 따라 다릅니다.

HotSpot은이를 "내재"로 취급하고 호출 사이트에 코드를 삽입합니다. 그것은 느린 오래된 C 코드가 아니라 기계 코드입니다. 이것은 또한 메서드의 서명 문제가 크게 사라짐을 의미합니다.

단순 복사 루프는 명백한 최적화를 적용 할 수있을만큼 간단합니다. 예를 들어 루프 풀기. 정확히 발생하는 일은 다시 구현에 따라 다릅니다.


2
이것은 매우 괜찮은 대답입니다 :), 특히. 내장 함수를 언급합니다. 보통 JIT에 의해 언 롤링되기 때문에 단순 반복이 더 빠를 수 있습니다
bestsss dec

4

내 자신의 테스트에서 다중 차원 배열을 복사하는 System.arraycopy ()는 for 루프를 인터리빙하는 것보다 10-20 배 빠릅니다.

float[][] foo = mLoadMillionsOfPoints(); // result is a float[1200000][9]
float[][] fooCpy = new float[foo.length][foo[0].length];
long lTime = System.currentTimeMillis();
System.arraycopy(foo, 0, fooCpy, 0, foo.length);
System.out.println("native duration: " + (System.currentTimeMillis() - lTime) + " ms");
lTime = System.currentTimeMillis();

for (int i = 0; i < foo.length; i++)
{
    for (int j = 0; j < foo[0].length; j++)
    {
        fooCpy[i][j] = foo[i][j];
    }
}
System.out.println("System.arraycopy() duration: " + (System.currentTimeMillis() - lTime) + " ms");
for (int i = 0; i < foo.length; i++)
{
    for (int j = 0; j < foo[0].length; j++)
    {
        if (fooCpy[i][j] != foo[i][j])
        {
            System.err.println("ERROR at " + i + ", " + j);
        }
    }
}

이것은 다음을 인쇄합니다.

System.arraycopy() duration: 1 ms
loop duration: 16 ms

9
이 질문은 오래되었지만 기록을 위해 : 이것은 공정한 벤치 마크가 아닙니다 (처음에 그러한 벤치 마크가 의미가 있는지 질문은 말할 것도 없습니다). System.arraycopy얕은 복사 ( 내부 s에 대한 참조float[]복사 됨)를 for수행하는 반면 중첩 루프는 전체 복사 ( floatby float)를 수행합니다 . 에 대한 변경 사항 fooCpy[i][j]foousing에 반영 System.arraycopy되지만 중첩 for루프는 사용하지 않습니다 .
misberner

4

몇 가지 이유가 있습니다.

  1. JIT는 수동으로 작성된 C 코드만큼 효율적인 저수준 코드를 생성하지 않을 것입니다. 낮은 수준의 C를 사용하면 일반 JIT 컴파일러에서 수행하기 거의 불가능한 많은 최적화가 가능합니다.

    수작업으로 작성된 C 구현의 몇 가지 트릭과 속도 비교를 보려면이 링크를 참조하십시오 (memcpy, 원칙은 동일 함).이 최적화 Memcpy를 확인 하면 속도가 향상됩니다.

  2. C 버전은 배열 구성원의 유형과 크기에 거의 독립적입니다. 배열 내용을 원시 메모리 블록 (예 : 포인터)으로 가져올 수있는 방법이 없기 때문에 Java에서 동일한 작업을 수행 할 수 없습니다.


1
자바 코드를 최적화 할 수 있습니다. 실제로 실제로 일어나는 것은 C보다 더 효율적인 기계 코드가 생성되는 것입니다.
Tom Hawtin-tackline

나는 때때로 JITed 코드가 실행되는 프로세서를 알고 있기 때문에 더 나은 지역 최적화가 될 것이라는 데 동의합니다. 그러나 "적시"이기 때문에 실행하는 데 더 오래 걸리는 모든 비 로컬 최적화를 사용할 수 없습니다. 또한 손으로 만든 C 코드와 일치 할 수 없습니다 (이는 프로세서를 고려하고 특정 프로세서에 대해 컴파일하거나 어떤 종류의 런타임 검사를 통해 JIT 이점을 부분적으로 무효화 할 수도 있음).
Hrvoje Prgeša 2010

1
나는 Sun JIT 컴파일러 팀이 그 많은 점에 대해 논박 할 것이라고 생각합니다. 예를 들어, HotSpot은 불필요한 메서드 디스패치를 ​​제거하기 위해 전역 최적화를 수행한다고 믿으며 JIT가 프로세서 특정 코드를 생성 할 수없는 이유가 없습니다. 그런 다음 JIT 컴파일러가 현재 애플리케이션 실행의 실행 동작을 기반으로 분기 최적화를 수행 할 수 있다는 점이 있습니다.
Stephen C

@Stephen C-브랜치 최적화에 대한 탁월한 포인트이지만 유사한 효과를 얻기 위해 C / C ++ 컴파일러로 정적 성능 프로파일 링을 수행 할 수도 있습니다. 또한 핫스팟에는 두 가지 작동 모드가 있다고 생각합니다. 데스크톱 응용 프로그램은 합리적인 시작 시간을 달성하기 위해 사용 가능한 모든 최적화를 사용하지 않는 반면 서버 응용 프로그램은 더 적극적으로 최적화됩니다. 대체로 몇 가지 이점이 있지만 일부는 느슨해집니다.
Hrvoje Prgeša

1
System.arraycopy에는 C를 사용하여 구현되지 않는 종류의 무효화의이 답변
Nitsan Wakart
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.