473,466 Members | 1,333 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

High Memory Usage Garbage Collection Question

Hello,

I'm exploring why one of my C# .NET apps has "high" memory usage, and
whether I can reduce the memory usage.

I have an app that wakes up and processes text files into a database
periodically. What happens, is that the app reads the contents of a
text file line by line into an ArrayList. Each element of the ArrayList
is a string representing a record from the file. The ArrayList is then
processed, and the arraylist goes out of scope.

As the file is read, and the ArrayList is extended, memory usage goes
from about 6Mb up to about 200Mb in some cases, depending on the size
of the file.

What is peculiar is that after the file has been read and closed, and
the ArrayList has gone out of scope, the memory usage does not not
reduce even after waiting several minutes.

My expectation is that most of the 200Mb would be garbage collected
soon after the ArrayList goes out of scope, and released back to the
system after several minutes, but this does not happen.

Another peculiar behaviour is that when the app wakes to process a
second file, memory usage remains at about 200Mb. After the second file
is processed, memory is still 200Mb. Note that when the second file
processed, memory does not jump from 200mb to 400mb back to 200mb.

I have tried using ArrayList's Clear() method to empty the arraylist
before it goes out of scope but that does not make any difference.

To try and make the problem reproducable, I wrote a test app that
simply reads a file into an arraylist, calls ArrayList.Clear() then
allows the ArrayList to fall out of scope, and sure enough the problem
is still there. Memory usage climbs in rough proportion to the file
size and remains there until the app ends, even if the file is read
several times, and even when the array list is out of cope, i.e. not
referenced.

Explicitly calling CG.Collect() made hardly any difference, although
calling GC.GetTotalMemory(true) shortly after processing each file did
reduce the amount of memory shown by task manager for the process.

I've re-written my app not to read the whole file into memory before
processing it (not a particularly good idea in the first place) and the
maximum memory usage has changed from 200mb to 35mb.

So what is really happening here?

In C# there's no way to explicitly release resources, so I do not have
direct control over releasing memory.

Assuming that the objects in the arraylist and the arraylist itself are
no longer referenced they should be candidates for garbage collection,
and should eventually be garbage collected, at which point the memory
they used should be released back to the system.

Perhaps these objects are no longer referenced, and the GC has decided
that as there's insufficient contention for memory on the server, it
won't bother garbage collecting them, resulting in apparently high
memory usage by the application.

I don't really know how to measure what's happening, any offers would
be greatfully received. I've included some test code below in the form
of a console app; you'll have to make the code process a suitably large
text file of your own though.

Regards,
Ian.

<!-- Code Starts here -->

using System;
using System.IO;
using System.Collections;

namespace SimpleFileReader
{
class SimpleFileReader
{
public static string readLineResponse;

[STAThread]
static void Main(string[] args)
{

Console.WriteLine( "Press return to create an app object, and run
the app." );
readLineResponse = Console.ReadLine();

SimpleFileReader app = new SimpleFileReader();
app.Execute();

Console.WriteLine( "Type quit to terminate the app." );

readLineResponse = "continue";

while ( true )
{
Console.WriteLine(
"\nHit return to continue, \n" +
" or type 'gc' to garbage collect, \n" +
" or type 'gtm' to call GC.GetTotalMemory(true), \n" +
" or type 'quit' and hit return.\n\n" );

readLineResponse = Console.ReadLine();

if ( "gc" == readLineResponse ) GC.Collect();
if ( "gtm" == readLineResponse ) GC.GetTotalMemory( true );
if ( "quit" == readLineResponse ) break;
}
}
public void Execute()
{
GetRecords( @"C:\SimpleFileReader\SLEXTRACTFILE050701.DAT" );
}
public void GetRecords( string fileName )
{
int recordCounter = 0;

ArrayList al = new ArrayList();

try
{
FileStream fs = File.OpenRead( fileName );
StreamReader sr = new StreamReader( fs );

string aLine = string.Empty;

Console.WriteLine( "Press return to read the file." );
readLineResponse = Console.ReadLine();

while( ( aLine = sr.ReadLine() )!= null )
{
if ( aLine.Length > 0 )
{
al.Add( aLine );
++recordCounter;
}
}

Console.WriteLine( recordCounter.ToString() + " record(s) read from
" + fileName );
Console.WriteLine( "File read. Press return to continue." );
readLineResponse = Console.ReadLine();

sr.Close();
fs.Close();
}
catch( System.Exception ex )
{
string extractFailedMessage =
"An exception occurred whilst extracting the contents of " +
fileName;

Console.WriteLine( extractFailedMessage + "\n" + ex.ToString() );
}

Console.WriteLine( "Press return to clear the arraylist" );
readLineResponse = Console.ReadLine();
al.Clear();
Console.WriteLine( "al.Clear() called." );

Console.WriteLine( "Press return to call GC.GetTotalMemory" );
readLineResponse = Console.ReadLine();
Console.WriteLine( "GC.GetTotalMemory just returned: " +
GC.GetTotalMemory( true ).ToString() );
}
}
}
<!-- Code Ends here -->

Jul 22 '05 #1
3 4101
Inline

Willy.

"Ian Taite" <ia*******@zen.co.uk> wrote in message
news:11**********************@g43g2000cwa.googlegr oups.com...
Hello,

I'm exploring why one of my C# .NET apps has "high" memory usage, and
whether I can reduce the memory usage.

I have an app that wakes up and processes text files into a database
periodically. What happens, is that the app reads the contents of a
text file line by line into an ArrayList. Each element of the ArrayList
is a string representing a record from the file. The ArrayList is then
processed, and the arraylist goes out of scope.

As the file is read, and the ArrayList is extended, memory usage goes
from about 6Mb up to about 200Mb in some cases, depending on the size
of the file.

What is peculiar is that after the file has been read and closed, and
the ArrayList has gone out of scope, the memory usage does not not
reduce even after waiting several minutes.

My expectation is that most of the 200Mb would be garbage collected
soon after the ArrayList goes out of scope, and released back to the
system after several minutes, but this does not happen.
After the functions ends with 200Mb string data in the Gen2 heap (yes, all
your string objects are aged objects) , the program returns to the main loop
and waits for a command (quit, gc, ...). But there is no reason for the GC
to run and clean-up the garbage, he quite happy with all the memory free in
the system ;-). Things would be different if you didn't have that much
memory available, the system would request the GC to clean-up after the
ArrayList became eligible for collection.
But wait, If you didn't have that memory free the system would start paging
because you need that memory badly because of your design which is somewhat
flawned.
It's flawned because I see no valid reason to store a complete text file in
a ArrayList (or array that's the same) one line per entry. Each entry has a
size of 16 + (line length in character * 2) (16 is the object overhead and,
I suppose the file is ANSI, while strings are unicode in .NET). That's a
reason not to store the whole file in memory, but only read small chuncks at
a time and process these. The small chunks (let's say 1000 lines at a time)
could be stored in a fixed length array, after which you can start
processing the lines stored in the array. Once this is done you refile the
array with the next chunk until the whole file is processd.
Another peculiar behaviour is that when the app wakes to process a
second file, memory usage remains at about 200Mb. After the second file
is processed, memory is still 200Mb. Note that when the second file
processed, memory does not jump from 200mb to 400mb back to 200mb.

I have tried using ArrayList's Clear() method to empty the arraylist
before it goes out of scope but that does not make any difference.

To try and make the problem reproducable, I wrote a test app that
simply reads a file into an arraylist, calls ArrayList.Clear() then
allows the ArrayList to fall out of scope, and sure enough the problem
is still there. Memory usage climbs in rough proportion to the file
size and remains there until the app ends, even if the file is read
several times, and even when the array list is out of cope, i.e. not
referenced.

Explicitly calling CG.Collect() made hardly any difference, although
calling GC.GetTotalMemory(true) shortly after processing each file did
reduce the amount of memory shown by task manager for the process.

I've re-written my app not to read the whole file into memory before
processing it (not a particularly good idea in the first place) and the
maximum memory usage has changed from 200mb to 35mb.

So what is really happening here?

In C# there's no way to explicitly release resources, so I do not have
direct control over releasing memory.

Assuming that the objects in the arraylist and the arraylist itself are
no longer referenced they should be candidates for garbage collection,
and should eventually be garbage collected, at which point the memory
they used should be released back to the system.

Perhaps these objects are no longer referenced, and the GC has decided
that as there's insufficient contention for memory on the server, it
won't bother garbage collecting them, resulting in apparently high
memory usage by the application.

I don't really know how to measure what's happening, any offers would
be greatfully received. I've included some test code below in the form
of a console app; you'll have to make the code process a suitably large
text file of your own though.

Regards,
Ian.

<!-- Code Starts here -->

using System;
using System.IO;
using System.Collections;

namespace SimpleFileReader
{
class SimpleFileReader
{
public static string readLineResponse;

[STAThread]
static void Main(string[] args)
{

Console.WriteLine( "Press return to create an app object, and run
the app." );
readLineResponse = Console.ReadLine();

SimpleFileReader app = new SimpleFileReader();
app.Execute();

Console.WriteLine( "Type quit to terminate the app." );

readLineResponse = "continue";

while ( true )
{
Console.WriteLine(
"\nHit return to continue, \n" +
" or type 'gc' to garbage collect, \n" +
" or type 'gtm' to call GC.GetTotalMemory(true), \n" +
" or type 'quit' and hit return.\n\n" );

readLineResponse = Console.ReadLine();

if ( "gc" == readLineResponse ) GC.Collect();
if ( "gtm" == readLineResponse ) GC.GetTotalMemory( true );
if ( "quit" == readLineResponse ) break;
}
}
public void Execute()
{
GetRecords( @"C:\SimpleFileReader\SLEXTRACTFILE050701.DAT" );
}
public void GetRecords( string fileName )
{
int recordCounter = 0;

ArrayList al = new ArrayList();

try
{
FileStream fs = File.OpenRead( fileName );
StreamReader sr = new StreamReader( fs );

string aLine = string.Empty;

Console.WriteLine( "Press return to read the file." );
readLineResponse = Console.ReadLine();

while( ( aLine = sr.ReadLine() )!= null )
{
if ( aLine.Length > 0 )
{
al.Add( aLine );
++recordCounter;
}
}

Console.WriteLine( recordCounter.ToString() + " record(s) read from
" + fileName );
Console.WriteLine( "File read. Press return to continue." );
readLineResponse = Console.ReadLine();

sr.Close();
fs.Close();
}
catch( System.Exception ex )
{
string extractFailedMessage =
"An exception occurred whilst extracting the contents of " +
fileName;

Console.WriteLine( extractFailedMessage + "\n" + ex.ToString() );
}

Console.WriteLine( "Press return to clear the arraylist" );
readLineResponse = Console.ReadLine();
al.Clear();
Console.WriteLine( "al.Clear() called." );

Console.WriteLine( "Press return to call GC.GetTotalMemory" );
readLineResponse = Console.ReadLine();
Console.WriteLine( "GC.GetTotalMemory just returned: " +
GC.GetTotalMemory( true ).ToString() );
}
}
}
<!-- Code Ends here -->

Jul 22 '05 #2
> Reading the whole file.

Sure, in the original design I thought the files would only be small, a
few 1000 records at most, but in fact 180,000 is more likely. I did
rewrite the app to "read-a-line - process-a-line" with much less memory
usage and hardly any difference in run time. Task Manager shows a
memory usage (is that "working set"?) of about 35Mb once the first file
has been processed, and it remains at 35mb when any more files are
processed, and it doesn't seem to matter whether the additional files
are say 5,000 or 180,000 records long.
Garbage collector


So you reckon that the garbage collector has decided not to clean up
because it has decided there's no contention for memory? If another
process started that used lots of memory, would that cause the GC in my
app to collect and free up those memory pages that were no longer in
use? I might see the working set trimmed right back and the memory
metric in task manager reduce in such a case. I suppose this is
something I could test with a 2nd memory hogging test app.

Ian.

Jul 24 '05 #3

"Ian Taite" <ia*******@zen.co.uk> wrote in message
news:11*********************@g49g2000cwa.googlegro ups.com...
Reading the whole file.


Sure, in the original design I thought the files would only be small, a
few 1000 records at most, but in fact 180,000 is more likely. I did
rewrite the app to "read-a-line - process-a-line" with much less memory
usage and hardly any difference in run time. Task Manager shows a
memory usage (is that "working set"?) of about 35Mb once the first file
has been processed, and it remains at 35mb when any more files are
processed, and it doesn't seem to matter whether the additional files
are say 5,000 or 180,000 records long.
Garbage collector


So you reckon that the garbage collector has decided not to clean up
because it has decided there's no contention for memory? If another
process started that used lots of memory, would that cause the GC in my
app to collect and free up those memory pages that were no longer in
use? I might see the working set trimmed right back and the memory
metric in task manager reduce in such a case. I suppose this is
something I could test with a 2nd memory hogging test app.

Ian.


Yes, if there is memory contention, the OS will ask the processes to trim
their WS and the CLR would initiate a ful collect, note that XP and w2k3
have other means to signal memory pressure. But don't worry, the GC will
clean-up earlier, when your code continues to process another file, the GC
will kick-in a do a full collect, that's why you saw a steady 200 MB memory
consumption in your runs.
If you need to know when exactly the GC kicks in you'll have to watch the
"CLR perfomance counters" using perfmon, especialy watch the Gen2 collection
counter and the gen1 and Gen2 sizes using the "CLR Memory Counters".

Willy.
Jul 24 '05 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

20
by: Philip Carnstam | last post by:
How come .Net applications use so much memory? Every application I compile uses at least 10 MB of memory, even the ones consisting of only a form and nothing else. If I minimize them though the...
25
by: Zeng | last post by:
I finally narrowed down my code to this situation, quite a few (not all) of my CMyClass objects got hold up after each run of this function via the simple webpage that shows NumberEd editbox. My...
7
by: Clement | last post by:
hi, i have an asp.net site and is using SQL Server 2k. i realize the aspnet_wp.exe memory usage keep growing and i will receive an error for the pages that call the sql connection. others page...
3
by: Ian Taite | last post by:
Hello, I'm exploring why one of my C# .NET apps has "high" memory usage, and whether I can reduce the memory usage. I have an app that wakes up and processes text files into a database...
8
by: Adrian | last post by:
Hi I have a JS program that runs localy (under IE6 only) on a PC but it has a memory leak (probably the known MS one!) What applications are there that I could use to look at the memory usage of...
3
by: Jim Land | last post by:
Jack Slocum claims here http://www.jackslocum.com/yui/2006/10/02/3-easy-steps-to-avoid-javascript- memory-leaks/ that "almost every site you visit that uses JavaScript is leaking memory". ...
2
by: roger.dunham | last post by:
I am trying to identify whether a .NET 1.1 application that I have written has a memory leak. I thought I understood how .NET memory management worked, but it appears that there is more to it...
9
by: deerchao | last post by:
I'm developing a WinForms application. It slowly eats up memory, one client reported that it took 200MB or more, and finnaly crashed. I myself noticed it's common to use up 30MB memory, but if I...
11
by: dhtml | last post by:
(originally mis-posted on m.p.s.jscript...) I've just closed all windows in Firefox and its using 244MB of memory. I have no idea why. I had GMail open, a page from unicode, the CLJ FAQ. ...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.