C#强制释放内存
最近对部门的爬虫做内存优化,起初重写了核心的爬取组件,内存占用确实低了很多,不过代码中有大量的文本处理,加之.net对string类型的特殊处理,爬虫长时间运行后,内存占用还是很高,使用VMMap分析后,发现Working Set中Managed Heap(托管堆)占用比例最大。
使用EmptyWorkingSet进行强制内存释放
尽管代码中也是用GC.Collect进行手动垃圾回收,但是效果始终不明显。
查资料的时候无意发现了EmptyWorkingSet这个WindowsAPI,可以尽可能多的从Working Set中回收内存,不少内存管理优化的软件也用到了这个API。
C#中的使用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // 声明 [DllImport("psapi.dll")] public static extern bool EmptyWorkingSet(IntPtr hProcess); // 使用 // 获取当前进程句柄 Process pProcess = Process.GetCurrentProcess(); // 尽可能多的清空Working Set释放内存 bool bRes = EmptyWorkingSet(pProcess.Handle); if (!bRes) { // empty working set fail } |
附:Windows中的进程的Working Set,Private Bytes和Virtual Bytes
- Working Set看成一个进程可以用到(但不一定会使用)的物理内存。即不引起page fault异常就能够访问的内存。
Working Set包含了可能被其他程序共享的内存, 例如DLL就是一个典型的可能被其他程序共享的资源。
所以所有进程的Working Set加起来有可能大于实际的物理内存。 - Private Bytes是只被本进程用占用的虚拟地址空间,不包括其他进程共享的内存。
Private Bytes既包括不引起page fault异常就能够访问的内存也包括引起page fault异常才能够访问的内存。
所以一般Private Bytes大于Working Set。但是如果一个进程和其他进程共享较多内存,也可能造成Working Set大于Private Bytes。 - Virtual Byte是整个进程占用的全部虚拟地址空间。32位Windows用户模式下,进程最大可以使用2GB,可以通过修改Boot.ini文件扩展为最大可以使用到3GB。
- Windows Task Manager中看到内存使用量是Working Set。