peer754
asked on
WMI API causes memory leak
Hi,
I'm developing a small in-house application to monitor the performance such as CPU usage, available memory, disk spaceour etc. I start with a small test settig up the CPU usage monitoring.
I am reading the CPU% once per second using WMI API function and then produce an average value each minute.
The problem with this is I get some memory leakage while looking at the process in the Taskmanager.
I've been googling this but all I found was a hotfix concerning leak in Win Server 2008 while I'm on XP/Win Server 2003 machines.
So, there's anyone here that could provide a working solution based on my code input, I'd be more than pleased!
Code:
I'm developing a small in-house application to monitor the performance such as CPU usage, available memory, disk spaceour etc. I start with a small test settig up the CPU usage monitoring.
I am reading the CPU% once per second using WMI API function and then produce an average value each minute.
The problem with this is I get some memory leakage while looking at the process in the Taskmanager.
I've been googling this but all I found was a hotfix concerning leak in Win Server 2008 while I'm on XP/Win Server 2003 machines.
So, there's anyone here that could provide a working solution based on my code input, I'd be more than pleased!
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Management;
using System.Configuration;
using System.Threading;
namespace ServerMonitoringConsole
{
class Program
{
static string clientName = "myName";
static string clientPwd = "myPwd";
static string domain = "ntlmdomain:myDomain";
static List<int> cpuLoads = new List<int>();
static string errorStr = "";
static void Main(string[] args)
{
int load = 0;
int avg = 0;
long mem = 0;
int cpuTimePeriod = 60;
string[] stringServers = { "serv1", "serv2" };
ConnectionOptions co = new ConnectionOptions();
co.Username = clientName;
co.Password = clientPwd;
co.Authority = domain;
List<ManagementScope> msList = new List<ManagementScope>();
msList.Add(new ManagementScope(@"\\" + stringServers[0] + @"\root\cimv2", co));
msList.Add(new ManagementScope(@"\\" + stringServers[1] + @"\root\cimv2", co));
ObjectQuery sq = new ObjectQuery("SELECT * FROM Win32_Processor");
List<ManagementObjectSearcher> mosList = new List<ManagementObjectSearcher>();
foreach (ManagementScope ms in msList)
{
ms.Connect();
mosList.Add(new ManagementObjectSearcher(ms, sq));
}
while (true)
{
load = 0;
int counter = 0;
while (cpuLoads.Count <= cpuTimePeriod)
{
Thread.Sleep(1000);
foreach (string server in stringServers)
{
GetCPUPerformance(server, ref load, mosList[counter]);
cpuLoads.Add(load);
counter++;
}
}
avg = (int)cpuLoads.Sum() / cpuTimePeriod;
cpuLoads.Clear();
}
}
static void GetCPUPerformance(string computerName, ref int cpuLoad, ManagementObjectSearcher mos)
{
using (ManagementObjectCollection moObjs = mos.Get())
{
foreach (ManagementObject mo in moObjs)
{
try
{
cpuLoad = Convert.ToInt32(mo["LoadPercentage"]);
}
finally
{
mo.Dispose();
}
}
}
}
}
}
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Once again, I did have GC.Collect() at the end on all methods but with no effect at all, i.e. still memory leaking on every call (one per second).
Ok, but I don't see how ensuring a synchronous thread creation should prevent memory leak?
Interesting to read about performance but this is not the main issue here, however I did try to move out the creation of the objects before entering the main loop which would be something like scenario #3
The connections are not closed since I reuse them according to your link (there's only 2 connections created in this example, one for each machine to monitor)
Ok, but I don't see how ensuring a synchronous thread creation should prevent memory leak?
Interesting to read about performance but this is not the main issue here, however I did try to move out the creation of the objects before entering the main loop which would be something like scenario #3
The connections are not closed since I reuse them according to your link (there's only 2 connections created in this example, one for each machine to monitor)
ASKER
My Console app is running on a XP machine Querying Win 2003 and Win XP machines. No noticable difference in the memory leak between the machines.
This Hotfix says "a memory leak of up to 20 bytes may occur for each WQL query to the decoupled WMI provider" while I have 20 KB / Query. Since I need to query several of our intranet machines (~ 40) every second, the machine hosting the Console app will quickly stop working normally so ...
Is there only one expert here in this area? :/
This Hotfix says "a memory leak of up to 20 bytes may occur for each WQL query to the decoupled WMI provider" while I have 20 KB / Query. Since I need to query several of our intranet machines (~ 40) every second, the machine hosting the Console app will quickly stop working normally so ...
Is there only one expert here in this area? :/
I posted a request for assistance to the moderator to see if we can get some additional experts to look at this.
ASKER
Thanks!
I've also been trying to find a work-around to prevent from querying too frequently as now now, every second.
I don't see how though regarding the CPU usage if you're not fine with taking a snapshot every minute or so.
If there was a way to get history CPU usage in one query / minute I'm done. Since I then could run my app as a scheduled task and hence, killing the thread and free the memory through OS normal scheduling.
I've also been trying to find a work-around to prevent from querying too frequently as now now, every second.
I don't see how though regarding the CPU usage if you're not fine with taking a snapshot every minute or so.
If there was a way to get history CPU usage in one query / minute I'm done. Since I then could run my app as a scheduled task and hence, killing the thread and free the memory through OS normal scheduling.
It's a strange problem no doubt.
I'm wondering if the same query/program would cause the memory leak when ran directly on the machine versus remotely.
I'm wondering if the same query/program would cause the memory leak when ran directly on the machine versus remotely.
ASKER
Exact same behaviour on local machine (XP SP3).
GetCPUPerformance(server, ref load, mosList[counter]);
the above code accesses 'mosList' at index 'counter' though counter obviously was independent of the size of the list.
i would have assumed that an exception was thrown when counter is equal or greater to size but in case it grows the list instead it could be a reason for the growing memory consumption.
in my opinion task manager is not suitable to detect leakage cause both the heap manager and the CLR garbage collector would reserve some of the freed memory for efficience and optimization reasons what means that task manager's report is not accurate.
Sara
ASKER
counter is not an issue here I'm afraid, it's only used to increment the objects corresponding to each server I want to monitor.
I have simplyfied the code only to one machine and one query (the CPU usage) + I have also tried querying the local machine to exclude the RPC from the error search.
Still, there's a leak according to, yes, the Task manager. I know looking at the Task manager won't give very accurate result in precise memory leak numbers but it still gives a hint that something's wrong.
In my last test on my local machine, I ran the code for about 15 minutes and the thread's memory increased to the double compare to when it started.
Here's my new simplyfied code:
I have simplyfied the code only to one machine and one query (the CPU usage) + I have also tried querying the local machine to exclude the RPC from the error search.
Still, there's a leak according to, yes, the Task manager. I know looking at the Task manager won't give very accurate result in precise memory leak numbers but it still gives a hint that something's wrong.
In my last test on my local machine, I ran the code for about 15 minutes and the thread's memory increased to the double compare to when it started.
Here's my new simplyfied code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Management;
using System.Configuration;
using System.Threading;
namespace ServerMonitoringConsole
{
class Program
{
static List<int> cpuLoads = new List<int>();
static void Main(string[] args)
{
int avg = 0;
int cpuReadPeriod = 5000; //Read CPU load every 5 sec
int cpuTimePeriod = 60000 / cpuReadPeriod;
while (true)
{
while (cpuLoads.Count <= cpuTimePeriod)
{
Thread.Sleep(cpuReadPeriod);
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_Processor"))
{
foreach (ManagementObject queryObj in searcher.Get())
{
try
{
Console.WriteLine("LoadPercentage: {0}", queryObj["LoadPercentage"]);
cpuLoads.Add(Convert.ToInt32(queryObj["LoadPercentage"]));
}
finally
{
queryObj.Dispose();
}
}
}
};
avg = (int)cpuLoads.Sum() / cpuTimePeriod;
cpuLoads.Clear();
Console.WriteLine("-----------------------------------");
Console.WriteLine("Win32_Processor instance");
Console.WriteLine("-----------------------------------");
Console.WriteLine("Average CPU LOAD = " + avg.ToString() + "%.");
GC.Collect();
}
}
}
}
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
I converted your latest code to vb and it seems to work without any issue.
I tested on Windows 7 and 2003
I tested on Windows 7 and 2003
ASKER
As suggested by one of the experts, removing some of the objects might have contributed to the final solution
ASKER