获取C盘卷序列号突然异常缓慢的问题排查与解决求助
问题:读取C盘卷序列号突然耗时超1分钟
原本正常的C盘卷序列号读取功能突然变慢,日志显示GetHdSerialString方法执行耗时超过1分钟,耗时点集中在获取Win32_LogicalDisk实例的环节。
原实现代码:
public static string GetHdSerialString() { try { WriteNLog("GetHdSerialString START ", eLogLevel.Info); using ManagementClass mangnmt = new ManagementClass("Win32_LogicalDisk"); using ManagementObjectCollection mcol = mangnmt.GetInstances(); string result = ""; foreach (ManagementObject strt in mcol.Cast<ManagementObject>()) { result += Convert.ToString(strt["VolumeSerialNumber"]); break; //只取第一个 } result = result.Insert(4, "-"); WriteNLog("GetHdSerialString END ", eLogLevel.Info); return result; } catch (Exception exc) { WriteNLog("GetHdSerialString exc:" + exc.Message, eLogLevel.Error); return String.Empty; } }
原因分析
- 原代码通过
Win32_LogicalDisk.GetInstances()枚举系统中所有逻辑磁盘,当系统存在离线网络驱动器、未响应的外接存储设备时,WMI会尝试逐一连接这些设备,触发超时等待,这是突然变慢的核心原因。 - 代码中虽然通过
break只取第一个实例,但WMI必须完成所有实例的枚举才会返回集合,因此无法避免前期的枚举耗时。
解决办法
方案1:优化WMI查询(直接定位C盘)
修改WQL查询语句,仅获取C盘的信息,避免枚举所有磁盘:
public static string GetHdSerialString() { try { WriteNLog("GetHdSerialString START ", eLogLevel.Info); string result = ""; // 直接查询C盘的逻辑磁盘信息 using ManagementObjectSearcher searcher = new ManagementObjectSearcher( "SELECT VolumeSerialNumber FROM Win32_LogicalDisk WHERE DeviceID='C:'"); foreach (ManagementObject disk in searcher.Get()) { result = Convert.ToString(disk["VolumeSerialNumber"]); break; } if (!string.IsNullOrEmpty(result)) { result = result.Insert(4, "-"); } WriteNLog("GetHdSerialString END ", eLogLevel.Info); return result; } catch (Exception exc) { WriteNLog("GetHdSerialString exc:" + exc.Message, eLogLevel.Error); return String.Empty; } }
方案2:使用Windows原生API(性能更稳定)
调用GetVolumeInformation Win32 API,绕过WMI,彻底避免枚举开销:
using System.Runtime.InteropServices; public static string GetCVolumeSerial() { try { WriteNLog("GetCVolumeSerial START ", eLogLevel.Info); uint serialNumber = 0; // 调用Win32 API获取C盘卷序列号 if (GetVolumeInformation(@"C:\", null, 0, ref serialNumber, out _, out _, null, 0)) { // 格式化序列号为XXXX-XXXX格式 string serial = serialNumber.ToString("X8"); string result = serial.Insert(4, "-"); WriteNLog("GetCVolumeSerial END ", eLogLevel.Info); return result; } WriteNLog("GetCVolumeSerial: Failed to get serial number", eLogLevel.Error); return string.Empty; } catch (Exception exc) { WriteNLog("GetCVolumeSerial exc:" + exc.Message, eLogLevel.Error); return String.Empty; } } // 导入Win32 API [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern bool GetVolumeInformation( string lpRootPathName, string lpVolumeNameBuffer, uint nVolumeNameSize, ref uint lpVolumeSerialNumber, out uint lpMaximumComponentLength, out uint lpFileSystemFlags, string lpFileSystemNameBuffer, uint nFileSystemNameSize);
内容的提问来源于stack exchange,提问作者Patrick
相关产品推荐
相关产品推荐

