정적 메서드와 인스턴스 메서드의 성능


108

내 질문은 정적 메서드 대 인스턴스 메서드의 성능 특성 및 확장 성과 관련이 있습니다. 이 시나리오에서는 모든 클래스 정의가 단일 어셈블리에 있고 여러 개의 개별 포인터 형식이 필요하다고 가정합니다.

치다:

public sealed class InstanceClass
{
      public int DoOperation1(string input)
      {
          // Some operation.
      }

      public int DoOperation2(string input)
      {
          // Some operation.
      }

      // … more instance methods.
}

public static class StaticClass
{
      public static int DoOperation1(string input)
      {
          // Some operation.
      }

      public static int DoOperation2(string input)
      {
          // Some operation.
      }

      // … more static methods.
}

위의 클래스는 도우미 스타일 패턴을 나타냅니다.

인스턴스 클래스에서 인스턴스 메서드를 해결하는 데는 StaticClass와 달리 시간이 걸립니다.

내 질문은 다음과 같습니다.

  1. 상태를 유지하는 것이 문제가되지 않을 때 (필드 나 속성이 필요하지 않음) 항상 정적 클래스를 사용하는 것이 더 낫습니까?

  2. 이러한 정적 클래스 정의가 상당수있는 경우 (예 : 각각 여러 정적 메서드가있는 100 개) 동일한 수의 인스턴스 클래스 정의에 비해 실행 성능이나 메모리 소비에 부정적인 영향을 미칩니 까?

  3. 동일한 인스턴스 클래스 내의 다른 메서드가 호출 될 때 인스턴스 확인이 계속 발생합니까? 예를 들어 동일한 인스턴스 this.DoOperation2("abc")내에서 와 같이 [this] 키워드를 사용합니다 DoOperation1.



"인스턴스 해결"이란 무엇을 의미합니까? IL 수준에서 "this"포인터는 다른 지역 변수와 마찬가지로 사용할 수 있습니다. 사실, 일부 오래된 CLR / JIT 버전에서는 'this'를 건드리지 않았다면 NULL에서 instance-method를 호출 할 수 있습니다. 코드가 방금 통과하고 아무것도 충돌하지 않았습니다. 이제 CLR / JIT에 명시적인 null- 모든 멤버 호출 확인 ..
quetzalcoatl

> vijaymukhi.com/documents/books/ilbook/chap8.htm 및 '호출 인스턴스'대 '호출'. 전자는 'this'매개 변수를 예상하고 후자는 그렇지 않습니다.
quetzalcoatl 2012 년

@Quetzalcoatl 혼동을 드려 죄송합니다. 질문은 동일한 인스턴스에서 메서드를 처리하는 방법이 더 많았으며 인스턴스가 자체적으로 해결되어야하는 경우입니다.
Bernie White

1
@quetzalcoatl 나는 "컴파일러가 this클래스가 인스턴스 메서드를 자체적으로 호출 할 때 어떤 것을 가리키는 지 검사하는 것을 제거 합니까?"라고 생각했습니다.
존 한나

답변:


152

이론적으로 정적 메서드는 추가 숨겨진 this매개 변수로 인해 인스턴스 메서드보다 약간 더 나은 성능을 발휘해야합니다 .

실제로 이것은 다양한 컴파일러 결정의 소음에 숨겨 질 정도로 거의 차이가 없습니다. (따라서 두 사람이 다른 사람보다 더 나은 결과를 "증명"할 수 있습니다.) 특히 this는 일반적으로 레지스터에서 전달되고 종종 해당 레지스터에서 시작되기 때문입니다.

이 마지막 요점은 이론적으로 객체를 매개 변수로 사용하고 동일한 객체의 인스턴스와 동등한 것보다 약간 덜 좋은 작업을 수행하는 정적 메서드를 예상해야 함을 의미합니다. 다시 말하지만, 차이가 너무 작아서 측정을 시도하면 다른 컴파일러 결정을 측정하게 될 것입니다. (특히 해당 참조가 레지스터에 있으면 전체 시간이 매우 높기 때문에).

실제 성능 차이는 자연스럽게 정적 인 작업을 수행하기 위해 메모리에 객체를 인위적으로 넣었는지, 아니면 자연스럽게 인스턴스가되어야하는 작업을 수행하기 위해 복잡한 방식으로 객체 전달 체인을 엉키고 있는지 여부에 달려 있습니다.

따라서 1 번입니다. 상태를 유지하는 것이 문제가되지 않을 때는 항상 정적 인 것이 낫습니다. 왜냐하면 그것이 정적 인 것이기 때문입니다 . 성능 문제는 아니지만 컴파일러 최적화를 훌륭하게 수행하는 전체적인 규칙이 있습니다. 누군가 이상하게 사용되는 경우보다 정상적인 사용으로 나타나는 경우를 최적화하려고 노력했을 가능성이 높습니다.

번호 2. 차이가 없습니다. 메타 데이터의 양, 실제 DLL 또는 EXE 파일에 얼마나 많은 코드가 있는지, 얼마나 많은 jitted 코드가 있는지에 따라 각 멤버에 대해 클래스 당 비용이 일정합니다. 이것은 인스턴스이든 정적이든 동일합니다.

항목 3 this도 마찬가지 this입니다. 그러나 참고 :

  1. this매개 변수는 특정 레지스터에 전달됩니다. 같은 클래스 내의 인스턴스 메서드를 호출 할 때, (이 은닉하고 어떤 이유로 사용되는 레지스터하지 않는 한) 그것은 가능성이 이미 레지스터에있을거야 따라서 어떠한 조치가를 설정이 필요하지 않습니다 this이 설정 될 필요가 무엇을 . 이것은 예를 들어 메서드에 대한 처음 두 매개 변수가 호출의 처음 두 매개 변수가되는 데 어느 정도 적용됩니다.

  2. thisnull이 아님 이 분명하므로 경우에 따라 호출을 최적화하는 데 사용할 수 있습니다.

  3. thisnull이 아님 이 분명하기 때문에 메서드 호출을 위조하기 위해 생성 된 코드가 어쨌든 필요한 일부 null 검사를 생략 할 수 있으므로 인라인 메서드 호출을 다시 더 효율적으로 만들 수 있습니다.

  4. 즉, null 검사는 저렴합니다!

인스턴스 메소드가 아닌 객체에 대해 작동하는 일반 정적 메소드가 http://joeduffyblog.com/2011/10/23/on-generics-and-some-of- 에서 논의 된 비용의 일부를 줄일 수 있다는 점은 주목할 가치가 있습니다. the-related-overheads / 는 주어진 정적이 주어진 유형에 대해 호출되지 않는 경우입니다. 그는 "제외로 확장 메서드가 일반적인 추상화를 더 많은 비용을 지불하도록 만드는 좋은 방법이라는 것이 밝혀졌습니다."

그러나 이것은 메서드에서 사용하는 다른 유형의 인스턴스화에만 관련되며 다른 방법은 존재하지 않습니다. 따라서 실제로 많은 경우에 적용되지 않습니다 (다른 인스턴스 메서드는 해당 유형을 사용하고 다른 코드에서는 해당 유형을 사용했습니다).

요약:

  1. 대부분 인스턴스와 정적의 성능 비용은 무시할만한 수준입니다.
  2. 예를 들어 정적을 남용하거나 그 반대의 경우 일반적으로 어떤 비용이 발생합니다. 정적과 인스턴스 사이의 결정의 일부로 만들지 않으면 올바른 결과를 얻을 가능성이 더 큽니다.
  3. 드물게 다른 유형의 정적 제네릭 메서드가 인스턴스 제네릭 메서드보다 생성되는 유형이 더 적어 드물게 사용되는 작은 이점을 가질 수있는 경우 가 있습니다 (그리고 "드물게"는 호출 빈도가 아니라 응용 프로그램의 수명). 그 기사에서 그가 말한 내용을 알게되면 어쨌든 대부분의 static-vs-instance 결정과 100 % 무관하다는 것을 알게 될 것입니다. 편집 : 그리고 그것은 대부분 jitted 코드가 아닌 ngen에서만 그 비용이 있습니다.

편집 : null 검사가 얼마나 저렴한 지에 대한 메모 (위에서 주장했습니다). .NET의 대부분의 null 검사는 null을 전혀 확인하지 않고 작동 할 것이라는 가정하에 수행 할 작업을 계속하며 액세스 예외가 발생하면 NullReferenceException. 따라서 대부분 개념적으로 C # 코드가 인스턴스 멤버에 액세스하기 때문에 null 검사를 포함 할 때 성공할 경우 비용은 실제로 0입니다. 예외는 일부 인라인 호출 (인스턴스 멤버를 호출 한 것처럼 동작하기를 원하기 때문)이고 필드를 쳐서 동일한 동작을 트리거하므로 매우 저렴하고 어쨌든 여전히 종종 제외 될 수 있습니다. (예를 들어 메서드의 첫 번째 단계가 필드에 액세스하는 것과 관련된 경우).


정적 대 인스턴스 질문이 캐시 일관성에 어떤 영향을 미치는지에 대해 언급 할 수 있습니까? 둘 중 하나에 의존하면 캐시 누락이 발생할 가능성이 더 높습니까? 이유를 설명하는 좋은 개요가 있습니까?
scriptocalypse

@scriptocalypse 정말 아닙니다. 명령 캐시에는 차이가 없으며 해당 수준에서는 this명시 적 매개 변수를 통해 또는이를 통해 데이터에 액세스하는 것 사이에 큰 차이가 없습니다 . 여기서 더 큰 영향은 데이터가 관련 데이터에 얼마나 가까운 지 (값 유형 필드 또는 배열 값이 참조 유형 필드의 데이터보다 더 가깝습니다) 및 액세스 패턴입니다.
Jon Hanna

"이론적으로, 우리는 객체를 매개 변수로 사용하고 그 객체를 사용하여 동일한 객체의 인스턴스와 동등한 것보다 약간 덜 좋은 정적 메서드를 기대해야합니다."-위의 샘플 메서드가 매개 변수를 문자열 대신 객체로 사용하면 비 정적이 더 낫습니까? 예를 들어 : 정적 메서드가 개체를 매개 변수로 사용하여 문자열로 직렬화하고 문자열을 반환합니다. 이 경우 비 정적 사용을 제안합니까?
batmaci

1
@batmaci 나는 obj.DoSomehting(2)그보다 약간 더 저렴할 것이라는 좋은 기회 가 있다는 것을 의미 DoSomething(obj, 2)하지만, 차이가 너무 적고 최종 컴파일에서 다를 수있는 작은 것들에 의존하여 전혀 걱정할 가치가 없다고 말했듯이. 문자열에 무언가를 직렬화하는 것처럼 비용이 많이 드는 작업을 수행하는 경우 (여기서는 플레이의 차이에 비해) 특히 의미가 없습니다.
Jon Hanna

이 훌륭한 대답에는 분명하지만 중요한 것이 하나 있습니다. 인스턴스 메서드에는 인스턴스가 필요하고 인스턴스를 만드는 것은 저렴하지 않습니다. 기본값조차도 ctor모든 필드를 초기화해야합니다. 인스턴스가 이미 있으면이 답변이 적용됩니다 ( "다른 모든 것이 동일 함"). 물론 비용이 많이 드는 경우 cctor정적 메서드도 느려질 수 있지만 첫 번째 호출에서만 인스턴스 메서드에 동일하게 적용됩니다. docs.microsoft.com/en-us/previous-versions/dotnet/articles/…
Abel

8

상태를 유지하는 것이 문제가되지 않을 때 (필드 나 속성이 필요하지 않음) 항상 정적 클래스를 사용하는 것이 더 낫습니까?

그렇습니다. 무언가 static를 선언 할 때 상태 비 저장 실행 의 의도 를 선언합니다 (필수는 아니지만 예상 할 수있는 의도).

이러한 정적 클래스가 상당히 많은 경우 (예를 들어 각각 여러 개의 정적 메서드가있는 100 개) 동일한 수의 인스턴스 클래스에 비해 실행 성능이나 메모리 소비에 부정적인 영향을 미칠까요?

그렇게 생각하지 마십시오. 정적 클래스가 정말로 스텔스 가 없다는 것을 확신하지 않는 한 , 메모리 할당을 엉망으로 만들고 메모리 누수가 발생하기 쉽습니다.

[this] 키워드를 사용하여 동일한 인스턴스 클래스 내에서 다른 메서드를 호출 할 때 인스턴스 확인이 계속 발생합니까?

점 에 대해서는 확실하지 않지만 (순전히 CLR의 구현 세부 사항입니다) 그렇다고 생각하십시오.


정적 메서드는 조롱 할 수 없습니다. TDD를 수행하거나 단위 테스트를 수행하면 테스트에 많은 피해를 줄 수 있습니다.
trampster

@trampster 왜? 그것은 단지 논리의 일부입니다. 당신이주는 것을 쉽게 조롱 할 수 있습니까? 올바른 행동을 얻으려면. 그리고 많은 정적 메서드는 어쨌든 함수의 논리의 개인적인 부분이 될 것입니다.
M. Mimpen

@ M.Mimpen 당신이 그것을 작은 개인 조각에 맡기면 벌금이 부과됩니다. 공개 방법이고 다른 닫는 곳에서 사용하고 테스트에서 수행하는 작업을 변경 해야하는 경우 파일 IO 또는 데이터베이스 액세스와 같은 것 또는 네트워크 호출 등, 정적 메서드에 넣는 경우 모의 할 수없는 종속성을 정적 메서드에 매개 변수로 삽입한다고 말하지 않는 한 모의 할 수 없게됩니다
trampster

-2

정적 메소드는 더 빠르지 만 OOP가 적습니다. 디자인 패턴을 사용하는 경우 정적 메소드는 잘못된 코드 일 가능성이 높고, 정적없이 비즈니스 로직을 더 잘 작성하고, 파일 읽기, WebRequest 등과 같은 일반적인 기능은 정적으로 더 잘 인식합니다. 대답


16
당신은 당신의 주장에 대해 어떠한 주장도하지 않았습니다.
ymajoros

2
@ fjch1997 2 명의 찬성자들은 다르게 생각하는 것 같습니다. : downvotes를 언급하는 것은 격려 stackexchange에 연습 meta.stackexchange.com/questions/135/...
ymajoros
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.