.NET中为何新分配对象内存地址重复?如何解决?
问题原因分析
你遇到的问题核心在于你打印的是栈上局部引用变量的地址,而非托管堆上Node实例的真实地址:
- 在C#中,
Node是引用类型,当你执行new Node(value)时,对象实例会被分配在托管堆上;而方法内的node变量是一个存储在栈上的引用(它的值是堆上实例的地址)。 - 每次调用
Add方法时,方法的栈帧会被重复利用,局部变量node在栈上的位置是固定的,所以你用&node获取的是这个栈上变量的地址,自然每次都完全相同。 - 你真正需要观察的是堆上每个Node实例的地址,而不是栈上引用变量的地址。
解决办法
要获取托管堆上对象实例的真实地址,可以通过两种常用方式实现:
方式一:使用Unsafe类(更简洁)
通过System.Runtime.CompilerServices.Unsafe类的AsPointer方法,直接获取引用指向的堆实例地址:
首先确保你的项目引用了System.Runtime.CompilerServices.Unsafe包(.NET Core/.NET 5+通常已内置),然后修改Add方法的unsafe代码块:
using System.Runtime.CompilerServices; // ... public void Add(int value) { Node node = new(value); _nodes.Add(node); unsafe { // 获取堆上Node实例的地址 ulong instanceAddress = (ulong)Unsafe.AsPointer(ref node); Console.WriteLine("Address of new node instance: {0}", instanceAddress); } }
方式二:使用GCHandle(更安全,适合需要固定对象的场景)
通过System.Runtime.InteropServices.GCHandle固定对象(防止GC移动它),然后获取其地址:
using System.Runtime.InteropServices; // ... public void Add(int value) { Node node = new(value); _nodes.Add(node); unsafe { GCHandle handle = GCHandle.Alloc(node, GCHandleType.Pinned); try { ulong instanceAddress = (ulong)handle.AddrOfPinnedObject(); Console.WriteLine("Address of new node instance: {0}", instanceAddress); } finally { handle.Free(); // 必须释放句柄,避免内存泄漏 } } }
验证效果
修改后运行代码,你会看到控制台输出的地址不再重复,每个Node实例的堆地址都是唯一的,完全符合你开发XOR链表的需求。
内容的提问来源于stack exchange,提问作者Jossean Yamil
相关产品推荐
相关产品推荐

