C#中对象是如何存储在内存中的?

4
我在想,对象是如何存储在内存中的呢?我知道有一个引用(类似指针)是一个整数值,它包含对象存储在内存中的位置——但是它究竟是如何存储的呢?
假设我有一个ClassC,它有int a、char b、long c、float d和short e,我知道每个变量都有一组自己的位来存储,但每个变量所需的位数不同——那么C# 知道当我写OBJ.c或OBJ.b时应该访问哪些位吗?
是否有可能将整个(非静态)对象转换为字节数组\位数组并反向转换回来?
显然,如果有类似于ClassC.TcpListener tcp的东西,它是一个引用,并存储为一个整数(至少它的字节数相同),但仍然,它如何区分整数和指针?

1
“但它究竟是如何存储的?” - 你能具体说明你在这里寻找什么吗?堆栈?大小端?还是其他什么? - Oded
1
请注意,这里的大多数答案都是实现细节。引用通常意味着不透明性 - 即使在大多数情况下它确实是一个指针,也不一定需要是。此外,在x64上,引用是64位而不是32位(“int”)。 - Marc Gravell
1
此外,ECMA-335 可以为您提供完整的答案。当然,它有点枯燥无味。 - Marc Gravell
我的意思是,如果我打开存储“对象A”的RAM位置,我会看到什么?(当然是以位为单位) - Mark Segal
2个回答

2

C# 实际上不知道如何访问对象中的成员。是JIT编译器决定对象的布局。

可以为成员添加属性,以便JIT编译器以特定方式放置成员,这将使访问所有成员作为内存块成为可能,但很少值得花费这种努力。

注意:在32位系统上,指针是32位(int),在64位系统上是64位(long)。


所以这就是为什么64位系统需要大量的内存 >.< - Mark Segal

2
一般来说,除非你在使用P/Invoke调用C库,否则你不需要关心这个问题。
“那么当我写OBJ.c或OBJ.b时,C#如何知道它应该访问哪些位?”
这取决于对象的StructLayout。有两种可能的LayoutKind
默认情况下是Sequential,其中字段按照它们声明的顺序存储,适当地对齐。默认情况下,包含五个字段的结构体将被存储为:
偏移量0-3: `int a` 偏移量4-5: `char b` 偏移量6-7: 填充 偏移量8-15: `long c` 偏移量16-19: `float d` 偏移量20-21: `short e`
一个类的布局可能会因为虚函数表指针、垃圾回收元数据等而略有不同,我不确定具体是如何工作的。另一个LayoutKind是Explicit,您可以明确指定字段偏移量。 能否将整个(非静态)对象转换为字节数组或位,并再次转换回来?这是比较可能的。
是的,Marshal 类可以让您这样做。请参见 StructureToPtrPtrToStructure
“它是一个引用并存储为 int”
指针不会存储为 int。在64位系统上无法使用。因此使用 IntPtr
“但是,它仍然如何区分 int 和指针?”
在哪个级别?C#?CIL?机器语言?

“对象的StructLayout”似乎有点自相矛盾... - Marc Gravell
Marshal 类并不总是允许您查看内存中的字节。它所做的是将其转换为适用于非托管代码的形式。往往情况下,这种转换并没有什么作用,但并非总是如此。 - svick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接