En teoría, un método estático debería funcionar ligeramente mejor que un método de instancia, en igualdad de condiciones, debido al this
parámetro oculto adicional .
En la práctica, esto hace tan poca diferencia que quedará oculto en el ruido de varias decisiones del compilador. (Por lo tanto, dos personas podrían "probar" una mejor que la otra con resultados en desacuerdo). Sobre todo porque this
normalmente se pasa en un registro y, para empezar, a menudo se encuentra en ese registro.
Este último punto significa que, en teoría, deberíamos esperar que un método estático que toma un objeto como parámetro y hace algo con él sea un poco menos bueno que el equivalente como instancia en ese mismo objeto. Sin embargo, una vez más, la diferencia es tan pequeña que si intenta medirla probablemente terminará midiendo alguna otra decisión del compilador. (Especialmente porque la probabilidad de que esa referencia esté en un registro todo el tiempo también es bastante alta).
Las diferencias reales de rendimiento se reducirán a si tienes objetos en la memoria de forma artificial para hacer algo que naturalmente debería ser estático, o estás enredando cadenas de paso de objetos de formas complicadas para hacer lo que naturalmente debería ser una instancia.
Por lo tanto, para el número 1. Cuando mantener el estado no es una preocupación, siempre es mejor ser estático, porque para eso es estático . No es un problema de rendimiento, aunque hay una regla general de jugar bien con las optimizaciones del compilador: es más probable que alguien se haya esforzado por optimizar los casos que surgen con el uso normal que los que surgen con un uso extraño.
Número 2. No importa. Hay una cierta cantidad de costo por clase para cada miembro en términos de la cantidad de metadatos que hay, la cantidad de código que hay en el archivo DLL o EXE real y la cantidad de código jitted que habrá. Esto es lo mismo ya sea de instancia o estático.
Con el ítem 3, this
es como this
hace. Sin embargo nota:
El this
parámetro se pasa en un registro particular. Al llamar a un método de instancia dentro de la misma clase, es probable que ya esté en ese registro (a menos que esté escondido y el registro se haya usado por alguna razón) y, por lo tanto, no se requiere ninguna acción para establecer el valor this
que debe establecerse. . Esto se aplica hasta cierto punto a, por ejemplo, que los dos primeros parámetros del método son los dos primeros parámetros de una llamada que realiza.
Como quedará claro que this
no es nulo, esto se puede utilizar para optimizar las llamadas en algunos casos.
Como quedará claro que this
no es nulo, esto puede hacer que las llamadas al método en línea sean más eficientes nuevamente, ya que el código producido para falsificar la llamada al método puede omitir algunas comprobaciones nulas que podría necesitar de todos modos.
Dicho esto, los cheques nulos son baratos.
Vale la pena señalar que los métodos estáticos genéricos que actúan sobre un objeto, en lugar de los métodos de instancia, pueden reducir algunos de los costos discutidos en http://joeduffyblog.com/2011/10/23/on-generics-and-some-of- the-associated-overheads / en el caso de que esa estática dada no se llame para un tipo determinado. Como él dice: "Dejando de lado, resulta que los métodos de extensión son una excelente manera de hacer que las abstracciones genéricas sean más rentables".
Sin embargo, tenga en cuenta que esto se relaciona solo con la creación de instancias de otros tipos utilizados por el método, que de otra manera no existen. Como tal, realmente no se aplica a muchos casos (algún otro método de instancia usó ese tipo, algún otro código en otro lugar usó ese tipo).
Resumen:
- En su mayoría, los costos de rendimiento de instancia frente a estático son inferiores a insignificantes.
- Los costos que existen generalmente vendrán cuando se abuse de la estática, por ejemplo, o viceversa. Si no lo convierte en parte de su decisión entre estático e instancia, es más probable que obtenga el resultado correcto.
- Hay casos raros en los que los métodos genéricos estáticos en otro tipo dan como resultado la creación de menos tipos que los métodos genéricos de instancia, lo que puede hacer que a veces tenga un pequeño beneficio para convertirlos en usados con poca frecuencia (y "rara vez" se refiere a los tipos con los que se usa en el vida útil de la aplicación, no con qué frecuencia se llama). Una vez que entienda de lo que está hablando en ese artículo, verá que de todos modos es 100% irrelevante para la mayoría de las decisiones estáticas frente a instancias. Editar: Y en su mayoría solo tiene ese costo con ngen, no con código jitted.
Editar: Una nota sobre cuán baratos son los controles nulos (que reclamé anteriormente). La mayoría de las comprobaciones de nulos en .NET no comprueban nulos en absoluto, sino que continúan con lo que iban a hacer con la suposición de que funcionará, y si ocurre una excepción de acceso, se convierte en un archivo NullReferenceException
. Como tal, principalmente cuando conceptualmente el código C # implica una verificación nula porque está accediendo a un miembro de instancia, el costo si tiene éxito es en realidad cero. Una excepción serían algunas llamadas en línea (porque quieren comportarse como si llamaran a un miembro de instancia) y simplemente presionan un campo para activar el mismo comportamiento, por lo que también son muy baratas y, de todos modos, a menudo se pueden omitir. (por ejemplo, si el primer paso del método implicaba acceder a un campo tal como estaba).