Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Compact Framework / April 2006

Tip: Looking for answers? Try searching our database.

GC does not release unused memory to the system in WinCE 4.2

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
MS - 20 Apr 2006 18:38 GMT
I've read in several sources that during garbage collection, the GC  will
release unused pages from the GC heap back to the OS.

Well this is not the case with my app.
Here is the code to reproduce the behaviour:
This sample code simply allocate about  2MB

private void btnCreateMemChunk_Click(object sender, System.EventArgs e) {
     if (al==null)
   al=new ArrayList();
  int Count=10000;
  ItemInfo ii=null;

  Exception eeee=null;

  GC.Collect();
  long before=System.GC.GetTotalMemory(true);

  this.tbMemo.Text+="Start
Mem(kb):"+((int)(before/1024)).ToString()+"\r\n";;

  for (int i=0;i<Count;i++) {
   try{
    ii=new ItemInfo((i.ToString()),new string('T',i%17),new
string('1',i%19),new string('9',i%7));
    al.Add(ii);
   }catch(Exception ee){
    eeee=ee;
    break;
   }

  }
  long after=System.GC.GetTotalMemory(true);
  if (eeee!=null)
    this.tbMemo.Text+="Exception: "+eeee.ToString()+"\r\n";
  this.tbMemo.Text+="End Mem(kb):"+((int)(after/1024)).ToString()+"\r\n";

 }

This code frees the array:
private void btnFree_Click(object sender, System.EventArgs e) {
if (this.al!=null)
   this.al=null;
 GC.Collect();

this.tbMemo.Text+="Allocated:"+GC.GetTotalMemory(false).ToString()+"\r\n";
}

When I start the program , it takes about 7MB of program memory, out of 9MB
free at the beginning.

First time I press the CreateMemChunk the allocated memory stays the same,
second time allocated memory goes to nearly 9MB.
(If I press again I get the Out of memory dialog.)

So I've pressed the button 2 times. CG tells me it has allocated about 4.2
MB of memory, and all programm memory on the device is allocated also.

Now I press btnFree. CG tells me it has allocated about 0,3 MB of memory.

But all of the program memory on the device is still taken from the GC !!!

If I try to run some other application I get the OOM dialog....

But if I press the CreateMemChunk it runs(even twice), which means that
there is plenty of space in th GC heap!!!!

So what can I do to make the GC release the unused 4MB of heap to the
system?

I've tried sending WM_HIBERNATE to CLR :

int res=WinAPI.SendMessage(0xffff,0x03FF,0,0);

but this does not help.

please help me,

thanks in advance
<ctacke/> - 20 Apr 2006 20:01 GMT
You have a misconception about how the GC works.  Calling Collect does not
instantly free memory in any measurable way.  It walks the GC Heap marking
reachable objects and then frees those that are not reachable.  The GC Heap
won't necessarily compact or shrink when you call it.

At first glance I would expect the GC Heap to shrink back to 1MB on the
first collection after you destroy your ArrayList (if this is CF 2.0
anyway).

This is not all of the code, so we can't exactly test it ourselves.

-Chris

> I've read in several sources that during garbage collection, the GC  will
> release unused pages from the GC heap back to the OS.
[quoted text clipped - 75 lines]
>
> thanks in advance
MS - 21 Apr 2006 09:59 GMT
Thanks for you reply.

My code runs on CF 1.0 SP3
Here is the full code of a sample to replicate the problem:

using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Data;

namespace MemTest
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
 private System.Windows.Forms.Button btnHibernateAll;
 private System.Windows.Forms.Button btnFree;
 private System.Windows.Forms.Button btnCreateChunk;
 private System.Windows.Forms.TextBox tbMemo;
 private System.Windows.Forms.Button button1;
 private System.Windows.Forms.Button button4;
 public ArrayList al=null;

 public Form1()
 {
  //
  // Required for Windows Form Designer support
  //
  InitializeComponent();

  //
  // TODO: Add any constructor code after InitializeComponent call
  //
 }
 /// <summary>
 /// Clean up any resources being used.
 /// </summary>
 protected override void Dispose( bool disposing )
 {
  base.Dispose( disposing );
 }
 #region Windows Form Designer generated code
 /// <summary>
 /// Required method for Designer support - do not modify
 /// the contents of this method with the code editor.
 /// </summary>
 private void InitializeComponent()
 {
  this.btnHibernateAll = new System.Windows.Forms.Button();
  this.btnFree = new System.Windows.Forms.Button();
  this.btnCreateChunk = new System.Windows.Forms.Button();
  this.tbMemo = new System.Windows.Forms.TextBox();
  this.button1 = new System.Windows.Forms.Button();
  this.button4 = new System.Windows.Forms.Button();
  //
  // btnHibernateAll
  //
  this.btnHibernateAll.Location = new System.Drawing.Point(160, 0);
  this.btnHibernateAll.Size = new System.Drawing.Size(80, 32);
  this.btnHibernateAll.Text = "Hibernate";
  this.btnHibernateAll.Click += new
System.EventHandler(this.btnHibernateAll_Click);
  //
  // btnFree
  //
  this.btnFree.Location = new System.Drawing.Point(80, 0);
  this.btnFree.Size = new System.Drawing.Size(80, 32);
  this.btnFree.Text = "Free";
  this.btnFree.Click += new System.EventHandler(this.btnFree_Click);
  //
  // btnCreateChunk
  //
  this.btnCreateChunk.Size = new System.Drawing.Size(80, 32);
  this.btnCreateChunk.Text = "Allocate";
  this.btnCreateChunk.Click += new
System.EventHandler(this.btnCreateChunk_Click);
  //
  // tbMemo
  //
  this.tbMemo.Location = new System.Drawing.Point(0, 32);
  this.tbMemo.Multiline = true;
  this.tbMemo.ScrollBars = System.Windows.Forms.ScrollBars.Both;
  this.tbMemo.Size = new System.Drawing.Size(232, 200);
  this.tbMemo.Text = "";
  //
  // button1
  //
  this.button1.Location = new System.Drawing.Point(0, 264);
  this.button1.Size = new System.Drawing.Size(80, 32);
  this.button1.Text = "Close";
  this.button1.Click += new System.EventHandler(this.button1_Click);
  //
  // button4
  //
  this.button4.Location = new System.Drawing.Point(144, 232);
  this.button4.Size = new System.Drawing.Size(88, 24);
  this.button4.Text = "GC Collect";
  this.button4.Click += new System.EventHandler(this.button4_Click);
  //
  // Form1
  //
  this.ClientSize = new System.Drawing.Size(234, 295);
  this.Controls.Add(this.button4);
  this.Controls.Add(this.button1);
  this.Controls.Add(this.btnHibernateAll);
  this.Controls.Add(this.btnFree);
  this.Controls.Add(this.btnCreateChunk);
  this.Controls.Add(this.tbMemo);
  this.Text = "Memory test";

 }
 #endregion

 /// <summary>
 /// The main entry point for the application.
 /// </summary>

 static void Main()
 {
  Application.Run(new Form1());
 }

 private void btnHibernateAll_Click(object sender, System.EventArgs e) {

  int res=WinAPI.SendMessage(0xffff,0x03FF,0,0);
  tbMemo.Text+="Hibernate sent!"+res.ToString()+"\r\n";
 }

 private void btnCreateChunk_Click(object sender, System.EventArgs e) {
  // System.Collections.ArrayList al=new ArrayList();
  if (al==null)
   al=new ArrayList();
  int Count=10000;
  ItemInfo ii=null;
  Exception eeee=null;

  GC.Collect();
  long before=System.GC.GetTotalMemory(true);
  this.tbMemo.Text+="Start GC Heap
Mem(kb):"+((int)(before/1024)).ToString()+"\r\n";;

  for (int i=0;i<Count;i++) {
   try{
    ii=new ItemInfo((i.ToString()),new string('T',i%17),new
string('1',i%19),new string('9',i%7));
    al.Add(ii);
   }catch(Exception ee){
    eeee=ee;
    break;
   }
  }
  long after=System.GC.GetTotalMemory(true);

  if (eeee!=null)
   this.tbMemo.Text+="Exception: "+eeee.ToString()+"\r\n";

  this.tbMemo.Text+="End CG Heap
Mem(kb):"+((int)(after/1024)).ToString()+"\r\n";

  long ss=System.Runtime.InteropServices.Marshal.SizeOf(ii);
  ii=new ItemInfo("0","0","0","0");

  ss=(after-before)/Count;
 }

 private void btnFree_Click(object sender, System.EventArgs e) {
  if (this.al!=null)
   this.al=null;

  this.tbMemo.Text+="Current GC
Heap:"+GC.GetTotalMemory(false).ToString()+"\r\n";
 }

 private void button1_Click(object sender, System.EventArgs e) {
  Close();
 }

 private void button4_Click(object sender, System.EventArgs e) {
  GC.Collect();
  this.tbMemo.Text+="Current GC
Heap:"+GC.GetTotalMemory(false).ToString()+"\r\n";
 }

}

public class ItemInfo {
 public string TruckNo="";
 public string ID="";
 public string Code128="";
 public DateTime Time;
 public string Name="";
 public static string delimiter=";";

 /// <summary>
 /// 0-áÒÔÉËÕÌßÔ Å ÚÁÒÅÄÅÎ ÏÔ ÂÁÚÁ
 /// 1-áÒÔÉËÕÌßÔ Å ÚÁÒÅÄÅÎ ÏÔ ÕÓÔÒÏÊÓÔ×Ï, ÎÑÍÁ ÇÏ × ÂÁÚÁÔÁ
 /// 2-áÒÔÉËÕÌßÔ Å ÉÚÔÒÉÔ!!!
 /// </summary>
 public int Status=0;

 public ItemInfo(string truckNo, string id, string code128, string name) {
  TruckNo=truckNo;
  ID=id;
  Code128=code128;
  Name=name;
  Time=DateTime.Now;
 }

 /// <summary>
 /// óßÚÄÁ×Á ÄÁÎÉ ÚÁ ÁÒÔÉËÕÌ ÏÔ ÒÅÄ
 /// </summary>
 /// <param name="Row"></param>
 public  ItemInfo(string Row) {
  string str=Row;
  string cell;
  int col=0;
  int endpos=0,startpos=0;

  while(((endpos = str.IndexOf(delimiter,startpos)) >= 0)&& (col<(5+1)) ) {
   cell=str.Substring(startpos,endpos-startpos);
   cell=cell.Trim();
   startpos=endpos+1;
   switch (col) {
    case 0: ID=cell; break;
    case 1: Code128=cell; break;
    case 2: TruckNo=cell; break;
    case 3:
     try {
      Time=DateTime.ParseExact(cell,"dd.MM.yy",System.Globalization.CultureInfo.CurrentCulture);
     }
     catch{}
     break;
   }

   col++;
  }
  //ðÏÓÌÅÄÎÁÔÁ ËÏÌÏÎÁ
  try {
   cell=str.Substring(startpos);
   DateTime
dTime=DateTime.ParseExact(cell,"hh:mm:ss",System.Globalization.CultureInfo.CurrentCulture);
   Time=Time.Add(new TimeSpan(dTime.Hour,dTime.Minute,dTime.Second));

  }
  catch{}

 }
 public override string ToString() {
  if ((Code128!=null)&&(Code128.Length>0))
   return Code128;
  if ((ID!=null)&&(ID.Length>0))
   return ID;
  return ID;
  //return base.ToString ();
 }

 public  string ToStringDB() {
  return
ID+delimiter+Code128+delimiter+TruckNo+delimiter+Time.ToString("dd.MM.yy")+delimiter+Time.ToString("hh:mm:ss");
 }

 //òÁ×ÎÉ ÓÁ ÓÁÍÏ ÁËÏ ÉÍ Å ÒÁ×ÅÎ ËÏÄ128 É
 public override bool Equals(object a) {
  if (  (((ItemInfo) a).Code128.Length>0) &&
   (this.Code128.Length>0)  &&
   (this.Code128==((ItemInfo) a).Code128))
   return true;
  return false;
 }

}

public class WinAPI{

 [System.Runtime.InteropServices.DllImport("coredll.dll")]
 public static extern int SendMessage(int hWnd, uint Msg, uint WParam, uint
LParam ) ;

 [System.Runtime.InteropServices.DllImport("coredll.dll")]
 public static extern int FindWindowW(String lpClassName,String
lpWindowName );

 // public extern static int SendMessage(IntPtr hwnd,uint msg, uint wParam,
uint lParam);
}

}

//----------------------------------------------------------------------------------------------------------

Steps to do:
1.Start the program.(initially I get about 9mb free program memory)
2. Press twice the "Allocate" button.(You will see there are 4MB in the GC
heap)
3. Press "Free"
4. Press GC Collect(You will see there are 0,3MB in the GC heap))
NOW:
5A. Try to start Word or IExplorer.  I get the out of memory box
OR
5B: Press twice the  "Allocate" button. The memory would be allocated inside
the GC heap.

For me this means that GC simply does not release the memory it uses, even
in a OOM situation.

Thanks in advance.

----- Original Message -----
From: "<ctacke/>" <ctacke_AT_OpenNETCF_com>
Newsgroups: microsoft.public.dotnet.framework.compactframework
Sent: Thursday, April 20, 2006 10:01 PM
Subject: Re: GC does not release unused memory to the system in WinCE 4.2

> You have a misconception about how the GC works.  Calling Collect does not
> instantly free memory in any measurable way.  It walks the GC Heap marking
[quoted text clipped - 90 lines]
>>
>> thanks in advance
<ctacke/> - 21 Apr 2006 15:07 GMT
What kind of device are you running on?  I tried on a PPC 2003 and followed
your directions and both pocket word and IE launch just fine with no
modifications to your code.  In fact I was able to allocate 10 times without
failure.

-Chris

> Thanks for you reply.
>
[quoted text clipped - 414 lines]
>>>
>>> thanks in advance
MS - 22 Apr 2006 10:13 GMT
I'm running on Windows CE 4.2 device, in fact I've tested this code on 4
different platforms.
1.Symbol's MC3000,
2.MC1000,
3.PPT8800(WinCE 4.1)
4.and on standart WindowsCE 4.2 emulator.

on all of these I get similar results.(It depends when on the initial
settings of the storage_to_program memory slider in the Control Panel)

On PPC2003 the behaviour of the operating systme in OOM case is different.
There, when you reach the maximum of the availabla program memory, the
device allocated some more from the available
storage. And since I suppose you were testing on device with 64MB RAM, it's
perfectly possible that you've allocated 20MB or more memory.
But even on that device, please, take a look that when you release these
20MB of data, not all of the program memory is released back to the system.

I've tested tha same program with CF2.0 on WinCE5.0, and everything works
perfectly(i.e
the memory is released back to the system), but unfortunately there is still
no CF2.0 for WinCE4.2.

I'm really desperate,
We are trying to port a big application running on hundreds of PPC2003
devices, but this stops our whole project.

Thanks in advance.

----- Original Message -----
From: "<ctacke/>" <ctacke_AT_OpenNETCF_com>
Newsgroups: microsoft.public.dotnet.framework.compactframework
Sent: Friday, April 21, 2006 5:07 PM
Subject: Re: GC does not release unused memory to the system in WinCE 4.2

> What kind of device are you running on?  I tried on a PPC 2003 and
> followed your directions and both pocket word and IE launch just fine with
[quoted text clipped - 424 lines]
>>>>
>>>> thanks in advance
<ctacke/> - 22 Apr 2006 11:52 GMT
CF 2.0 for CE 4.2:

http://www.microsoft.com/downloads/details.aspx?FamilyID=6548dd53-a418-42d9-a481
-19ba3ceca1a6&displaylang=en%20


-Chris

> I'm running on Windows CE 4.2 device, in fact I've tested this code on 4
> different platforms.
[quoted text clipped - 461 lines]
>>>>>
>>>>> thanks in advance
MS - 22 Apr 2006 12:12 GMT
Thank you very much!

I'll give it a try tomorrow!

----- Original Message -----
From: "<ctacke/>" <ctacke_AT_OpenNETCF_com>
Newsgroups: microsoft.public.dotnet.framework.compactframework
Sent: Saturday, April 22, 2006 1:52 PM
Subject: Re: GC does not release unused memory to the system in WinCE 4.2

> CF 2.0 for CE 4.2:
>
[quoted text clipped - 469 lines]
>>>>>>
>>>>>> thanks in advance
TDC - 25 Apr 2006 16:38 GMT
MS, did this fix your problem?

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.