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 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.
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