Click here to Skip to main content
Click here to Skip to main content
Go to top

Boosting Performance with Fields

, 17 Aug 2009
Rate this:
Please Sign up or sign in to vote.
A potentially significant amount of performance gain and code size reduction can be achieved by making use of internal fields rather than designing applications with a blanket use of public properties.

Introduction

A potentially significant amount of performance gain and code size reduction can be achieved by making use of internal fields rather than designing applications with a blanket use of public properties. Public properties are frequently blindly considered a “good programming practice” without giving thought to whether that practice is applicable.

Optimization removes much, but not all, of the penalty of properties in the .NET environment. We present some of the philosophical arguments in the conclusion.

Arguments for Public Properties

When a value requires exposure to other developer’s assemblies, defining it as a property has merit. For example, in version 1 of our assembly we define the following property and field:

public int MyProperty { get; set; }

public int MyField;

In time, others are now using our assembly and are dependent on it. Later we find an issue that we must address, such as the values must always be positive. We can change our property as below to be tolerant to consumers of our assembly passing negative values.

public int MyProperty
{
    get { return this.myProperty; }
    set { this.myProperty = value >= 0 ? value : 0; }
}
private int myProperty;

Users of our assembly do not have to recompile to make use of our update. However, we cannot do the same to our field. To add the value checking code to our field, we must first turn it into a property, and if we do so, we break compatibility with previous versions. This would make public fields not a “good programming practice.”

Mechanics of Properties and Fields

There is a cost to using a property rather than a field. A field is essentially a location in memory that we can get and set values with a single instruction to the CPU (“mov” in the case of the X86). However a property is a way of auto-generating code. The two methods below are the resulting code:

public int get_MyProperty()
{
    return this.myProperty;
}
public void set_MyProperty(int value)
{
    this.myProperty = value >= 0 ? value : 0;
}
private int myProperty;

We are no longer using a single CPU instruction to access our value, but are calling methods to get or set the value. The CPU must now execute a call instruction to the method and the method must do the “mov” instruction and then a return instruction. Adding to the additional instructions are the pushing and popping of the instruction pointer to the stack. The result is at least five times the amount of work for a property as compared to a field. There are many techniques used in CPU hardware to increase efficiency, such as doing the pushing and popping in parallel, but that is beyond our scope.

Internal Fields

We see that using properties for public values has merit and a cost that we must bear. However, this weight does not have to be applied to values that are used internally within our assembly. If a given value, at least for the current version, is used only within our assembly, we should not expose it publicly, but rather keep it internal as below.

internal int MyValue;

The overhead of properties is eliminated by using a field. If we are now coding version 2 of our assembly and find that we have to add our validation logic, we can simply change our field into a property and recompile. Typically, no other parts of our assembly are impacted, and no compatibility issues arise.

internal int MyValue
{
    get { return this. myValue; }
    set { this. myValue = value >= 0 ? value : 0; }
}
private int myValue;

Accessing Public Properties as Internal Fields

We can gain some internal efficiency with public properties by internally exposing the underlying values. This allows our assembly to make use of the value as a field while allowing for updates in future versions.

public int MyProperty
{
    get { return this.myProperty; }
    set { this.myProperty = value; }
}
internal int myProperty;

If we find we have to add our validation logic, we can do a search on all internal references to our field and change them as appropriate to using the public property. Since the changes we are making impact only our assembly, there is no impact on other users.

Public Fields When We Own the Solution

When multiple assemblies are used in our solution, but those assemblies are not shared outside of our solution, we can make use of public fields in the same way we have described for internal fields.

Even when we have a large team working on a single solution, we can expose values as public fields, as the “MyValue” example above. Anyone can change a field into a property when necessary without disrupting the efforts of the other members of the team. By employing this policy, we can achieve a balance of efficiency and updatability.

Optimization Removes Much of the Weight

The compilers in the Microsoft .NET Framework offer significant optimization. The “debug” version performs as described above, but the “release” code removes the call to the getter and setter and accesses the backing field directly.

This optimization performs remarkably, but is not complete. Incrementing a field is a single instruction, while incrementing a property remains three. This optimization may also be present in future versions of the compiler.

libraryClass.MyField++;
inc        dword ptr [esi+8]
libraryClass.MyProperty++;
mov        eax,dword ptr [esi+4]
inc        eax
mov        dword ptr [esi+4],eax

Note: To view the disassembly of optimized code in Visual Studio 2008, you must change some of the default options. Click "Tools" then "Options".
In the "Debugging General" uncheck "Enable Just My Code (Managed Only)" and "Suppress JIT optimization on module Load (Managed Only)".

However, a property’s getter and setter definitions remain and the JIT compiler must perform the optimization each time the application loads. Fields are, in essence, optimized before the JIT compiler starts, and require one entry into the assembly’s manifest which results in a smaller file.

Philosophical Arguments

Some will argue that it is simplest to use properties always and let the compiler make the decisions. We suggest that when you write code, you should write what you intend to have executed. Properties sometimes execute as fields, whereas fields always execute as fields.

If you write for more than one environment, then you cannot assume the optimizations will carry forward. The concepts of properties and fields are essentially universal, even with 8-bit embedded processors, but optimization is not.

In many cases, such as many data binding scenarios, properties are required and fields are not an option.

Many times, especially in internal applications, the debug version is the version that goes into production use. When this is the case, the optimization advantage is gone.

Compile time during application development, application start time, and file sizes are all impacted by the choice of properties versus fields. For one instance, the impact is insignificant. For complex applications, the impact is real.

Conclusion

The great value of public properties comes into play when we are developing assemblies that are used by others outside of our solution. When we own the solution and make blind use of properties, we add significant, unnecessary overhead to our development effort and impair the application’s performance.

For a solo programmer or a large team, a refined policy of using fields and properties wisely can result in a performance gain and code size reduction.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

ShofarNexus
Founder ShofarNexus Corporation
United States United States
ShofarNexus™ is software project started in 1998 with a lot of testing and rejecting of methodologies. Our goals were fast startup and execution, a clean presentation and reliable data distribution. We take ReST to the extreme. We focus some on eye-candy and mostly on the meat and vegetables that are good for business.
 
ShofarNexus™ mentality is well described by Antoine de Saint-Exupéry who wrote “Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.”
 
ShofarNexus™ is single-handedly written by John Kozlowski, with over 35 years of software development experience and a lot of hardware design in the first two decades.

Comments and Discussions

 
GeneralMy vote of 1 PinmemberHeywood18-Aug-09 3:39 
GeneralMy vote of 1 Pinmembersrikalwa17-Aug-09 19:12 
Generalwtf ;/ Pinmemberradioman.lt17-Aug-09 18:24 
GeneralRe: wtf ;/ PinmemberHeywood18-Aug-09 3:46 
GeneralRe: wtf ;/ Pinmemberr_hyde18-Aug-09 6:46 
GeneralMy vote of 1 PinmemberGünther M. FOIDL9-Aug-09 3:54 
GeneralRe: My vote of 1 PinmemberShofarNexus17-Aug-09 12:40 
GeneralMy vote of 2 Pinmembertalley9-Aug-09 3:50 
GeneralMy vote of 2 PinmemberBoBsEd9-Aug-09 1:27 
GeneralMy vote of 2 PinmemberChristoph Weber8-Aug-09 10:14 
GeneralRe: My vote of 2 PinmemberShofarNexus8-Aug-09 11:56 
GeneralRe: My vote of 2 PinmemberHeywood18-Aug-09 3:55 
GeneralMoot Point PinmemberMW_Justin8-Aug-09 9:24 
GeneralRe: Moot Point PinmemberShofarNexus8-Aug-09 9:51 
GeneralRe: Moot Point PinmemberMW_Justin8-Aug-09 10:02 
GeneralRe: Moot Point PinmemberShofarNexus8-Aug-09 11:49 
GeneralRe: Moot Point PinmemberMW_Justin8-Aug-09 12:05 
GeneralRe: Moot Point PinmemberShofarNexus8-Aug-09 13:05 
GeneralRe: Moot Point PinmemberFZelle9-Aug-09 1:03 
GeneralRe: Moot Point Pinmemberstikves9-Aug-09 3:14 
GeneralRe: Moot Point PinmemberMW_Justin9-Aug-09 4:58 
I guess I'm still not sure what you are getting at... You have claimed that accessing a public property of another assembly requires a call instruction (major performance hit) and a public field access does not. My code showed that after 100 million access there was no difference. You've said this is because my test class contained no other code. I don't understand this or what difference that would make. Can you provide an example?
 
The numbers don't lie, there is no significant performance difference between the two. You provided the IL generated by the cs compiler (csc.exe) here is the actual code that is executed on my machine after the IL has been jitted.
 
Loop 1 field access:
00000058  xor         eax,eax 
0000005a  inc         dword ptr [esi+4] 
0000005d  inc         eax  
0000005e  cmp         eax,5F5E100h 
00000063  jl          0000005A 
 
Loop 2 property access:
00000073  xor         edx,edx 
00000075  mov         eax,dword ptr [esi+8] 
00000078  inc         eax  
00000079  mov         dword ptr [esi+8],eax 
0000007c  inc         edx  
0000007d  cmp         edx,5F5E100h 
00000083  jl          00000075 
 
You notice that the first loop is better as the field is directly incremented where as the second the incremented register is moved to the memory location. This is where the slight difference in speed is coming from and slight cannot be emphasized enough a few thousandths of a second after 100 million iterations. Notice further that there is no call instruction which is where an actual performance hit would come from and in which case I would also recommend not using properties. If you compile this in debug mode however, there is a call instruction and you will get performance that is an order of magnitude worse for the property access.
 
Does this make sense? If you still think that there really is a performance hit please provide an example as I am at a loss as to how to make this more clear.
 
~Justin_H

GeneralRe: Moot Point PinmemberShofarNexus17-Aug-09 12:38 
GeneralInteresting PinmentorTrollslayer8-Aug-09 7:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140926.1 | Last Updated 17 Aug 2009
Article Copyright 2009 by ShofarNexus
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid