.NET 7 AOT 的使用以及 .NET 与 Go 互相调用( 二 )


.NET 7 AOT 的使用以及 .NET 与 Go 互相调用

文章插图
C# 调用库函数这一部分的代码示例 , 是从笔者的一个开源项目中抽取出来的 , 这个项目封装了一些获取系统资源的接口 , 以及快速接入 Prometheus 监控 。
不过很久没有更新了 , 最近没啥动力更新 , 读者可以点击这里了解一下这个项目:
https://github.com/whuanle/CZGL.SystemInfo/tree/net6.0/src/CZGL.SystemInfo/Memory
因为后续代码需要 , 所以现在请开启 “允许不安全代码” 。
本小节的示例是通过使用 kernel32.dll 去调用 Windows 的内核 API(Win32 API) , 调用 GlobalMemoryStatusEx 函数 检索有关系统当前使用物理内存和虚拟内存的信息 。
使用到的 Win32 函数可参考:https://learn.microsoft.com/zh-cn/windows/win32/api/sysinfoapi/nf-sysinfoapi-globalmemorystatusex
关于 .NET 调用动态链接库的方式 , 在 .NET 7 之前 , 通过这样调用:
[DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)][return: MarshalAs(UnmanagedType.Bool)]internal static extern Boolean GlobalMemoryStatusEx(ref MemoryStatusExE lpBuffer);在 .NET 7 中 , 出现了新的操作方式 [LibraryImport]
文档是这样介绍的:
Indicates that a source generator should create a function for marshalling arguments instead of relying on the runtime to generate an equivalent marshalling function at run time.指示源生成器应创建用于编组参数的函数 , 而不是依赖运行库在运行时生成等效的编组函数 。简单来说 , 就是我们要使用 AOT 写代码 , 然后代码中引用到别的动态链接库时 , 需要使用 [LibraryImport] 引入这些函数 。
笔者没有在 AOT 下测试过 [DllImport] , 读者感兴趣可以试试 。
新建两个结构体 MEMORYSTATUS.csMemoryStatusExE.cs
MEMORYSTATUS.cs
public struct MEMORYSTATUS{internal UInt32 dwLength;internal UInt32 dwMemoryLoad;internal UInt32 dwTotalPhys;internal UInt32 dwAvailPhys;internal UInt32 dwTotalPageFile;internal UInt32 dwAvailPageFile;internal UInt32 dwTotalVirtual;internal UInt32 dwAvailVirtual;}MemoryStatusExE.cs
public struct MemoryStatusExE{/// <summary>/// 结构的大小 , 以字节为单位 , 必须在调用 GlobalMemoryStatusEx 之前设置此成员 , 可以用 Init 方法提前处理/// </summary>/// <remarks>应当使用本对象提供的 Init  , 而不是使用构造函数!</remarks>internal UInt32 dwLength;/// <summary>/// 一个介于 0 和 100 之间的数字 , 用于指定正在使用的物理内存的大致百分比(0 表示没有内存使用 , 100 表示内存已满) 。/// </summary>internal UInt32 dwMemoryLoad;/// <summary>/// 实际物理内存量 , 以字节为单位/// </summary>internal UInt64 ullTotalPhys;/// <summary>/// 当前可用的物理内存量 , 以字节为单位 。这是可以立即重用而无需先将其内容写入磁盘的物理内存量 。它是备用列表、空闲列表和零列表的大小之和/// </summary>internal UInt64 ullAvailPhys;/// <summary>/// 系统或当前进程的当前已提交内存限制 , 以字节为单位 , 以较小者为准 。要获得系统范围的承诺内存限制 , 请调用GetPerformanceInfo/// </summary>internal UInt64 ullTotalPageFile;/// <summary>/// 当前进程可以提交的最大内存量 , 以字节为单位 。该值等于或小于系统范围的可用提交值 。要计算整个系统的可承诺值 , 调用GetPerformanceInfo核减价值CommitTotal从价值CommitLimit/// </summary>internal UInt64 ullAvailPageFile;/// <summary>/// 调用进程的虚拟地址空间的用户模式部分的大小 , 以字节为单位 。该值取决于进程类型、处理器类型和操作系统的配置 。例如 , 对于 x86 处理器上的大多数 32 位进程 , 此值约为 2 GB , 对于在启用4 GB 调整的系统上运行的具有大地址感知能力的 32 位进程约为 3 GB。/// </summary>internal UInt64 ullTotalVirtual;/// <summary>/// 当前在调用进程的虚拟地址空间的用户模式部分中未保留和未提交的内存量 , 以字节为单位/// </summary>internal UInt64 ullAvailVirtual;/// <summary>/// 预订的 。该值始终为 0/// </summary>internal UInt64 ullAvailExtendedVirtual;internal void Refresh(){dwLength = checked((UInt32)Marshal.SizeOf(typeof(MemoryStatusExE)));}}

经验总结扩展阅读