5

I have a part of code that operates on large arrays of double (containing about 6000 elements at least) and executes several hundred times (usually 800) .

When I use standard loop, like that:

double[] singleRow = new double[6000];
int maxI = 800;
for(int i=0; i<maxI; i++)
{
singleRow = someObject.producesOutput();
//...
// do something with singleRow
// ...
}

The memory usage rises for about 40MB (from 40MB at the beggining of the loop, to the 80MB at the end).

When I force to use the garbage collector to execute at every iteration, the memory usage stays at the level of 40MB (the rise is unsignificant).

double[] singleRow = new double[6000];
int maxI = 800;
for(int i=0; i<maxI; i++)
{
singleRow = someObject.producesOutput();
//...
// do something with singleRow
// ...
GC.Collect()
}

But the execution time is 3 times longer! (it is crucial)

How can I force the C# to use the same area of memory instead of allocating new ones? Note: I have the access to the code of someObject class, so if it would be needed, I can change it.

1
  • 1
    I'd like to see what you do with the array after you get it and how the producesOutput works, if possible. Commented May 6, 2010 at 20:00

3 Answers 3

7

Why are you allocating a large, empty singleRow only to overwrite it? Maybe you should be passing the array in to have its values modified in place. This would allow you to reuse it.

double[] singleRow = new double[6000];
int maxI = 800;
for(int i=0; i<maxI; i++)
{
    someObject.FillWithOutput(singleRow);
    //...
    // do something with singleRow
    // ...
}

If the method sometimes fills less than 6000 elements, it could simply return the fill count. Alternately, you could use a List<double>, which will allow resizing.

Sign up to request clarification or add additional context in comments.

Comments

3

Make singleRow a parameter and pass it in to the call to producesOutput every time...

Basically your producesOutput method is probably allocating a new array every time, and the re-assignment of singleRow just marks the old memory as available to remove, but doesn't run the GC for performance reasons.

5 Comments

No need to make it a ref if the array is of fixed length.
Arguably, ref would cause no direct harm and would show the intent to modify the parameter. Still, I don't think it's the right thing to do.
@Steven, using ref seems to be a little bit clearer. @John, Thanks for your help. Pity I cannot accept two answers ;)
Well, ref would be needed if the array was to be replaced by another one as opposed to being modified in place. Since you really do want to modify in place, the ref might be misleading. The deeper confusion is that it allows the method to do something that it, in fact, never does. (I upvoted John's answer, too.)
I need to check the convention used in our project. I guess I will leave the ref with a proper comment to explain the usage.
0

You aren't going to like this, but if you have to force GC you're doing something wrong. Keep in mind that memory may grow until there's pressure to trigger a GC - this is a GOOD thing because it means GC doesn't run until it has to.

Here's a silly-sounding test, but it might shed some light on what is happening. Inside FillWithOutput() comment out most of its functionality. Then run your loop and measure memeory. Incrementally un-comment out pieces of it until you see a blip. Now your're getting closer to what is causing the 'leak'.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.