4

I am experiencing some memory performance issues with my code and I am not sure which is the best way to pass parameters to my methods. I will give a short example about this.

I have for instance this class:

class Person
{
    public string Name { get; set; }
    public bool IsMale { get; set; }
    public string Address { get; set; }
    public DateTime DateOfBirth { get; set; }
}

and then I am using it like this:

    static void Main(string[] args)
    {
        Person person = new Person {
            Name = "John",
            Address = "Test address",
            DateOfBirth = DateTime.Now,
            IsMale = false };

        int age = CalculateAge(person);

        int age2 = CalculateAge(person.DateOfBirth);
    }

    private static int CalculateAge(Person person)
    {
        return (DateTime.Now - person.DateOfBirth).Days;
    }

    private static int CalculateAge(DateTime birthDate)
    {
        return (DateTime.Now - birthDate).Days;
    }

Now in my app I have lots of method calls where the entire object (an object with lots of properties not like this "Person" object from my example) was passed as parameter and I am thinking to improve the code by sending to the methods only the properties that they need, but currently I am not sure how this will improve memory performance.

How is it better regarding memory usage, to send the entire Peron object to my method like CalculateAge(person); or to send just the property that is used into the method like CalculateAge(person.DateOfBirth);?

First I thought that calls like this CalculateAge(person.DateOfBirth); (sending as parameters only the needed properties instead of the entire object) are using less memory but in the end after tests I noticed that app performs slower, and now I am not sure if these changes or others were slowing down my app.

5
  • 1
    How did you determine you were having memory issues due to parameter passing? Have you done a performance/memory analysis of your app?
    – AlG
    Commented Jan 21, 2016 at 19:04
  • Yes, I was using a StopWatch instance to count the running time, and was bigger...
    – Clock
    Commented Jan 21, 2016 at 19:08
  • 2
    time is money, not memory.
    – jgauffin
    Commented Jan 21, 2016 at 19:37
  • 2
    Timing your app using StopWatch is not an effective way to find performance issues. It can be a decent way to compare algorithms but it requires MANY iterations to give menaingful results. Cosider looking at commercial profilers like Ants or dotTrace to get a more accurate understanding of possible performance issues. Passing parameters is very likely not one of your problems.
    – D Stanley
    Commented Jan 21, 2016 at 19:40
  • passing individual properties is going to be even worse if you think it's bad now. When you pass the object as a whole, you are sending a reference to it (basically c#'s version of a pointer) so one reference. If you send multiple properties instead, you're sending several references + some value copies (DateTime, bool). Any performance bottleneck you are experiencing must be coming from something else. Commented Jan 24, 2016 at 0:15

2 Answers 2

4

There are three situations to consider here:

  1. Passing a class object vs. another class object
  2. Passing a struct value vs. a class object
  3. Passing multiple class/structs vs. a single class

In terms of memory only the first case is going to be an equal trade: it takes as much memory to pass a string Name as it takes to pass Person person.

Passing a struct, such as DateTime, may take more memory or less memory, depending on the size of the struct. For DateTime the size is (currently) eight bytes. For a smaller by-value object, e.g. a struct with a single short, you would need fewer bytes. For larger structs, e.g. DateTimeOffset, you would need more bytes.

Passing multiple objects or values in most cases is going to require more memory than passing a single class object. The only exception would be passing several very small structs.

Independently from considering the memory impact you should consider the logical structure of your API before deciding on the strategy.

Passing a Person to an API that computes the age creates a dependency between the age-computing API and the Person. Passing DOB separately, on the other hand, creates a dependency between Person and the caller of the API.

If you plan to use age-computing API exclusively with Person objects, then passing Person makes sense. Moreover, you should consider adding a computed property directly to the Person class,

On the other hand, if you plan to use age-computing API with other objects (animals, buildings, etc.) you would be better off passing DOB.

5
  • How can i determine the size of e.g. DateTime? The sizeof and the Marshal.SizeOf do not work here..
    – Bashn
    Commented Jan 21, 2016 at 19:32
  • @Bashn sizeof should work in unsafe context. Commented Jan 21, 2016 at 19:36
  • Isn't somehting like sending the parameters through reference or value influencing this memory performance ? So when they are passed through value, copies are created, so this is not the best way when sending the entire object. So in my case I should consider that they are already send through reference... and my strategy of sending just the needed parameters instead of the entire onject is a good aproach when sending them through value.
    – Clock
    Commented Jan 21, 2016 at 19:42
  • 2
    @user5631730 structs are passed by value (DateTime is a struct; int, double, Guid, byte, Nullable<T> are all structs as well, to name a few). Some of them could be pretty large - bigger than an object reference. You can pass structs by reference if you make your method receive a ref DateTime instead of just DateTime, but you should be careful with that, because out and ref semantic is reserved for situations when you want to write back a new struct. Passing a class object, on the other hand, costs you the same no matter how many properties the object has. Commented Jan 21, 2016 at 19:49
  • Thank you @dasblinkenlight for explanations !
    – Clock
    Commented Jan 21, 2016 at 19:52
1

Basically, if I'm not completely wrong, this should not matter. All that is passed to the method is a pointer to your object, which is 8 byte on a 64-bit machine (see here).

It should only make a difference if you can reduce the number of objects you pass (n times 8 byte), but also this should never be a problem in a "standard application".

EDIT: As @Bashn pointet out, DateTime is a struct and is therefor completely copied to the stack on method call. Yet it does not matter in this case, because DateTime is 8 bytes big. Depending on the size of the given struct, this may impose more or less overhead on method calling.

Still, passing paramters should never lead to a memory problem. How did you find out your memory issue?

10
  • And re. that last paragraph: I guess fewer parameters would also be more likely to be able to be passed in registers rather than via the stack?
    – CompuChip
    Commented Jan 21, 2016 at 19:06
  • @CompuChip: Possible, I'm not really that into CIL. Commented Jan 21, 2016 at 19:07
  • 1
    Since DateTime is a struct it gets copied on the stack before invoking the method (if i am not mistaking :p) but interesting question +1
    – Bashn
    Commented Jan 21, 2016 at 19:07
  • Oh yeah, you a totally right, didn't realize that DateTime is a struct. Have to update my answer. +1 Commented Jan 21, 2016 at 19:10
  • I just count the app running time using a StopWatch and noticed that more time is used...
    – Clock
    Commented Jan 21, 2016 at 19:11

Not the answer you're looking for? Browse other questions tagged or ask your own question.