문제

나는 최근에 관리되는 언어가 모국어(특히 C#과 C++)보다 느린지(또는 빠른지)에 관한 토론을 읽었습니다.토론에 참여한 한 사람은 관리 언어의 JIT 컴파일러가 포인터를 사용하는 언어에서는 불가능한 참조 관련 최적화를 수행할 수 있을 것이라고 말했습니다.

내가 알고 싶은 것은 포인터가 아닌 참조에서 가능한 최적화의 종류는 무엇입니까?

논의는 메모리 사용량이 아니라 실행 속도에 관한 것이었습니다.

도움이 되었습니까?

해결책

다음과 같은 몇 가지 이점이 있습니다. JIT 컴파일 Wikipedia에서 언급된 내용:

JIT 코드는 일반적으로 인터프리터보다 훨씬 더 나은 성능을 제공합니다.또한 많은 최적화가 런타임에만 가능하므로 일부 또는 많은 경우 정적 컴파일보다 더 나은 성능을 제공할 수 있습니다.

  1. 컴파일은 대상 CPU와 애플리케이션이 실행되는 운영 체제 모델에 맞게 최적화될 수 있습니다.예를 들어 JIT는 CPU가 SSE2 CPU 명령어를 지원한다는 것을 감지하면 SSE2 CPU 명령어를 선택할 수 있습니다.정적 컴파일러를 사용하면 인라인 어셈블리를 사용하여 두 가지 버전의 코드를 작성해야 합니다.
  2. 시스템은 프로그램이 현재 환경에서 실제로 어떻게 실행되는지에 대한 통계를 수집할 수 있으며 최적의 성능을 위해 재배치하고 다시 컴파일할 수 있습니다.그러나 일부 정적 컴파일러는 프로필 정보를 입력으로 사용할 수도 있습니다.
  3. 시스템은 전역 코드 최적화를 수행할 수 있습니다(예:라이브러리 함수의 인라인) 동적 링크의 장점을 잃지 않고 정적 컴파일러 및 링커에 내재된 오버헤드 없이.특히, 전역 인라인 대체를 수행할 때 정적 컴파일러는 런타임 검사를 삽입하고 개체의 실제 클래스가 인라인 메서드를 재정의하는 경우 가상 호출이 발생하는지 확인해야 합니다.
  4. 이는 정적으로 컴파일된 가비지 수집 언어로 가능하지만 바이트코드 시스템은 더 나은 캐시 활용을 위해 메모리를 더 쉽게 재배열할 수 있습니다.

포인터 대신 참조를 사용하는 것과 직접적으로 관련된 것을 생각할 수 없습니다.

다른 팁

C ++에는 최적화 측면과 관련된 참조의 두 가지 장점이 있습니다.

  1. 기준은 일정합니다 (전체 평생 동안 동일한 변수를 나타냅니다)

    이로 인해 컴파일러가 어떤 이름이 동일한 기본 변수를 참조하는지를 추론 할 수 있으므로 최적화 기회를 만듭니다. 컴파일러가 참조로 더 잘할 것이라는 보장은 없지만 ...

  2. 참조는 무언가를 참조하는 것으로 가정합니다 (무효 기준이 없습니다)

    "아무것도 언급하지 않는다"(널 포인터와 동일)를 만들 수있는 참조는 만들어 질 수 있지만 널 포인터를 만드는 것만 큼 쉽지는 않습니다. 이로 인해 NULL 참조 점검을 생략 할 수 있습니다.

그러나 이러한 장점 중 어느 것도 관리되는 언어로 직접적으로 이어지지 않으므로 토론 주제의 맥락에서 그 관련성을 보지 못합니다.

일반적으로 말하면, 참조는 다른 장소의 동일한 객체를 참조 할 수 있습니다.

'포인터'는 참조를 구현하는 메커니즘의 이름입니다. C ++, Pascal, C ... 포인터가 있습니다. C ++는 '참조'라는 다른 메커니즘 (약간 다른 사용 사례와 함께)을 제공하지만 본질적으로 일반 참조 개념의 구현입니다.

따라서 참고 문헌이 정의에 따라 포인터보다 더 빠르거나 느리게하는 이유는 없습니다.

실제 차이점은 JIT 또는 클래식 'Up Front'컴파일러를 사용하는 것입니다. JIT는 UP 전면 컴파일러에서 사용할 수없는 데이터를 고려할 수 있습니다. 그것은 '참조'개념의 구현과 관련이 없습니다.

다른 답변이 옳습니다.

나는 프로그램 카운터가 기능 호출을 포함하지 않는 단단한 루프 (예 : 문자열 비교)와 같이 많은 시간을 소비하는 코드에 있지 않는 한 모든 최적화는 차이를 만들지 않을 것이라고 덧붙였다.

관리 프레임 워크의 객체 참조는 C ++의 전달 된 기준과 매우 다릅니다. 무엇을 특별하게 만드는지 이해하려면 쓰레기 수집 객체 참조없이 다음 시나리오가 기계 레벨에서 어떻게 처리되는지 상상해보십시오. 메소드 "FOO"는 문자열을 반환하여 다양한 컬렉션에 저장되어 다른 코드 조각으로 전달됩니다. 더 이상 문자열이 필요하지 않으면 저장에 사용 된 모든 메모리를 되 찾을 수 있어야하지만 문자열을 사용하는 마지막 코드가 어떤 코드가 될지 확실하지 않습니다.

비 GC 시스템에서 모든 컬렉션에는 자체 문자열 사본이 있거나 문자열에 문자를 보유하는 공유 객체에 대한 포인터가 포함 된 무언가를 담을 필요가 있습니다. 후자의 상황에서, 공유 객체는 마지막 포인터가 언제 제거 될지 알아야합니다. 이것을 처리 할 수있는 다양한 방법이 있지만, 모두의 필수적인 일반적인 측면은 포인터에 대한 포인터를 복사하거나 파괴 할 때 공유 객체에 통보되어야한다는 것입니다. 이러한 알림에는 작업이 필요합니다.

대조적으로 GC 시스템에서, 프로그램은 메타 데이터로 장식되어 주어진 객체 참조를 유지하기 위해 주어진 시간에 스택 프레임의 레지스터 또는 일부를 사용합니다. 쓰레기 수집주기가 발생하면 쓰레기 수집기는이 데이터를 구문 분석하고 모든 라이브 객체를 식별하고 보존하며 다른 모든 것을 핵무기시켜야합니다. 그러나 다른 시간에 프로세서는 관련된 객체에 알리지 않고도 좋아하는 패턴 또는 시퀀스에서 참조를 복사, 교체, 셔플 또는 파괴 할 수 있습니다. 다중 프로세서 시스템에서 포인터 사용 알림을 사용할 때 다른 스레드가 동일한 객체에 대한 참조를 복사하거나 파괴 할 수있는 경우, 필요한 알림 스레드 -SAFE를 만들기 위해 동기화 코드가 필요합니다. 대조적으로, GC 시스템에서 각 프로세서는 다른 프로세서와 동작을 동기화하지 않고도 참조 변수를 언제든지 변경할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top