我想用 C# 编写一个客户端,它检查用户是否登录到不同的客户端。客户端应 24/7 全天候运行并使用每个客户端的一些状态信息刷新数据库。
我的问题是:命令行工具占用越来越多的内存,所以我认为我分配的内存永远不会被释放是一个问题。
我认为我正在创建一个 ManagementScope,但我不能为它使用所有 Dispose() 方法。
这是我的代码:
static void Main(string[] args)
{
Ping pingSender = new Ping();
PingOptions options = new PingOptions();
string sqlconnectionstring = "Data Source=(local)\\SQLEXPRESS;Initial Catalog=clientstat;User ID=...;Password=....;Integrated Security=SSPI";
SqlConnection clientread = new SqlConnection(sqlconnectionstring);
clientread.Open();
// Use the default Ttl value which is 128,
// but change the fragmentation behavior.
options.DontFragment = true;
string username = "";
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 120;
while (true)
{
SqlCommand clientcommand = new SqlCommand("SELECT * FROM Client WHERE StateID = @stateid", clientread);
clientcommand.Parameters.Add(new SqlParameter("stateid", 1));
SqlDataReader clientreader = clientcommand.ExecuteReader();
while (clientreader.Read())
{
string ipadress = Convert.ToString(clientreader["IP"]);
string clientid = Convert.ToString(clientreader["ID"]);
if (ipadress != string.Empty && clientid != string.Empty)
{
// First Try To Ping Computer
PingReply reply = pingSender.Send(ipadress, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
try
{
ManagementScope managementScope = new ManagementScope((@"\\" + ipadress + @"\root\cimv2"));
managementScope.Options.Username = "....";
managementScope.Options.Password = "...";
managementScope.Options.EnablePrivileges = true;
// ObjectQuery to Check if User is logged on
ObjectQuery objectQuery = new ObjectQuery("SELECT * FROM Win32_ComputerSystem");
ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(managementScope, objectQuery);
ManagementObjectCollection querycollection = managementObjectSearcher.Get();
foreach (ManagementObject mo in querycollection)
{
// Check Here UserName
username = Convert.ToString(mo["UserName"]);
if (username != "")
{
Console.WriteLine(ipadress + " " + username);
}
}
querycollection.Dispose();
managementObjectSearcher.Dispose();
}
catch (Exception x)
{
Console.WriteLine(x.Message);
}
}
}
else
{
Console.WriteLine(clientid + " has no IP-Adress in Database");
}
}
clientcommand.Dispose();
clientreader.Close();
clientreader.Dispose();
}
}
}
有什么我可以在这里改进的想法或建议吗?或者究竟是什么问题?
提前致谢
请您参考如下方法:
想法 1:
您必须处置 ManagementObject释放非托管 COM 资源。
不幸的是,there is a bug in the Dispose它的实现。 Here are more details关于它。
鸣谢应转到 this answer它提供了使用 GC.Collect()
的解决方法。不幸的是,它需要成本。
这就是为什么最好使用计数器每 n 次循环执行一次 GC.Collect
,您将手动调整一个 n 值,直到性能可以接受为止。
无论如何,我会尝试使用反射调用 ManagementObject Dispose()。
想法 2:
一般来说,为多个查询重复使用一个打开的连接是不好的,因为它会阻止连接池机制发挥最佳作用。因此,如果使用的话,sqlconnection 可能会保留资源。
相反,请在循环中包含 SqlConnection
create/open 和 close/dispose,与 this question 相关.