c#中的fixed关键字核心用途是防止垃圾回收器在不安全代码中移动托管堆上的对象,确保与非托管代码互操作或进行指针操作时内存地址的稳定性;它通过在unsafe上下文中固定数组、字符串、值类型等的地址,使指针操作成为可能,但仅在fixed块内有效,且需谨慎使用以避免性能损耗和安全风险;最佳实践包括最小化作用域、优先使用span<t>等安全替代方案,并做好异常处理和代码文档说明,以平衡性能与安全性。

C#中的
fixed
unsafe
要固定变量内存,你必须在一个
unsafe
fixed
fixed
using System;
public unsafe class MemoryPinningExample
{
public static void Main(string[] args)
{
int[] numbers = { 10, 20, 30, 40, 50 };
// 使用fixed关键字固定数组的第一个元素的地址
fixed (int* ptr = numbers)
{
// 在这个fixed块内,numbers数组的内存地址是稳定的
Console.WriteLine($"数组第一个元素的地址:{(long)ptr:X}");
Console.WriteLine($"通过指针访问第一个元素:{ptr[0]}");
// 我们可以像C/C++那样进行指针算术
int* secondElementPtr = ptr + 1;
Console.WriteLine($"通过指针访问第二个元素:{secondElementPtr[0]}");
// 甚至可以修改值
ptr[0] = 100;
Console.WriteLine($"修改后,数组第一个元素:{numbers[0]}");
}
// 一旦离开fixed块,内存就不再被固定,GC可以自由移动它
string message = "Hello, C# Fixed!";
// 也可以固定字符串的字符数据
fixed (char* charPtr = message)
{
Console.WriteLine($"字符串第一个字符的地址:{(long)charPtr:X}");
Console.WriteLine($"通过指针访问第一个字符:{charPtr[0]}");
}
Console.WriteLine("\n尝试固定一个值类型实例:");
MyStruct myStruct = new MyStruct { X = 10, Y = 20 };
fixed (MyStruct* structPtr = &myStruct) // 注意这里需要&操作符
{
Console.WriteLine($"MyStruct实例的地址:{(long)structPtr:X}");
Console.WriteLine($"通过指针访问MyStruct.X:{structPtr->X}");
}
}
}
public struct MyStruct
{
public int X;
public int Y;
}fixed
在我看来,
fixed
这“钉子”最常见的使用场景,就是与非托管代码打交道。想象一下,你通过P/Invoke调用一个C++编写的DLL函数,这个函数需要一个指向内存缓冲区的指针。如果C#的GC在你把指针传给C++函数后,悄悄地把这个缓冲区挪走了,那C++函数拿到的指针就成了“野指针”,结果就是程序崩溃,或者更糟——数据损坏。
fixed
此外,在某些极度性能敏感的场景,或者需要直接操作内存结构(比如解析二进制协议数据),
fixed
fixed
使用
fixed
正确使用它,有几个要点:
unsafe
fixed
unsafe
fixed
fixed
fixed
fixed
fixed
struct
&
fixed (MyStruct* ptr = &myStruct)
fixed (int* ptr = myArray)
fixed (char* ptr = myString)
unsafe
fixed size buffer
fixed byte buffer[128];
fixed
fixed
举个例子,如果你需要处理一个大型字节数组,并将其传递给一个非托管函数:
using System;
using System.Runtime.InteropServices; // 通常用于P/Invoke
public unsafe class AdvancedFixedExample
{
// 假设这是一个非托管函数,需要一个字节数组指针和长度
[DllImport("YourNativeLibrary.dll")]
private static extern int ProcessData(byte* dataPtr, int length);
public static void ProcessMyByteArray(byte[] data)
{
if (data == null || data.Length == 0) return;
fixed (byte* ptr = data) // 固定整个字节数组的起始地址
{
// 在这里,ptr指向data数组的第一个字节,且地址在块内稳定
int result = ProcessData(ptr, data.Length);
Console.WriteLine($"Native function returned: {result}");
// 也可以直接操作数组内容
for (int i = 0; i < 5 && i < data.Length; i++)
{
ptr[i] = (byte)(ptr[i] + 1); // 示例:修改前5个字节
}
}
// 离开fixed块后,ptr不再有效,data数组可被GC移动
Console.WriteLine($"数组第一个元素现在是: {data[0]}");
}
public static void Main(string[] args)
{
byte[] myData = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
ProcessMyByteArray(myData);
}
}在这个例子中,
fixed
ProcessData
data
fixed
当你在C#中决定使用
fixed
一个显而易见的挑战就是安全性。
fixed
另一个挑战是性能影响。尽管
fixed
最佳实践方面:
fixed
fixed
fixed
fixed
Span<T>
Memory<T>
Span<T>
fixed
fixed
unsafe
fixed
总的来说,
fixed
以上就是C#的fixed关键字有什么用途?怎么固定变量内存?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号