【问题标题】:CLR - where are reference addresses stored?CLR - 参考地址存储在哪里?
【发布时间】:2011-10-30 17:08:14
【问题描述】:

我是编程新手,这给我带来了很多困惑。

假设我们有以下语句:

Int32 i = 1;

i的内容存储在内存中,将是四个字节:00000000 00000000 00000000 00000001

CLR 以后如何访问这个内存位置? CLR 会在某处存储此内存块的地址吗?

【问题讨论】:

  • 在 c# 中使用非别名类型通常是不好的做法。 Int32 应该只是“int” Int64 是“long”
  • @Mranz 考虑到他的问题更多是关于clr 而不是C#,使用.NET 名称而不是C# 别名可能更好。
  • @xanatos 它被标记为 c#
  • @Mranz 他正在使用 C# 语法。我知道 :-) 最后你做了正确的事告诉他他通常不会使用Int32,但这是可以使用它的千分之一的情况(因为最后, C# 规范没有说明内存)
  • @Mranz:使用类型名称而不是别名关键字的原因有很多,例如,当您想强调类型的大小时,这对于网络和序列化代码很常见/ 或互操作,以产生特定的布局。

标签: c# clr


【解决方案1】:

System.Int32 是值类型,不使用引用。

事实上,如果编译器可以找到一个 CPU 寄存器在其整个生命周期中保存它,那么局部变量可能根本就不会在内存中。

如果它在内存中,将通过向堆栈指针 (ESP) 或包含它的引用类型(class,C#)对象的地址添加偏移量来找到它的地址。

在从 JIT 生成的代码中,值类型的变量与本机代码使用的变量没有区别(没有对象头或类似的东西)。

【讨论】:

    【解决方案2】:

    编译器会跟踪变量的位置,以便它可以创建以正确方式访问它的代码。

    在这种情况下,您声明了一个局部变量,因此它将在堆栈上分配。

    程序不会访问特定地址的变量,而是作为基指针的偏移量,指向当前方法的栈帧。

    例如,将变量设置为 1 的代码在编译为 32 位应用程序的机器代码时可能如下所示:

    mov dword ptr [ebp-8],1
    

    ebp 寄存器指向堆栈帧的顶部,因此在这种情况下,i 变量被分配了 8 个字节。

    【讨论】:

    • 谢谢。你的回答让我明白了。我要研究内存堆栈是如何工作的。
    【解决方案3】:

    假设正常情况下,如果i 是一个局部变量,它将被保存在堆栈中。 .NET 的abstract VM 是一个基于堆栈的VM。

    我将在 Intel/AMD 上添加 i 不会以这种方式保存 :-) Intel/AMD 是 little endian。所以会是00000001 00000000 00000000 00000000

    我稍微混合一下...现在... IL 语言和 .NET abstract VM 是基于“纯”堆栈的,所以有一个堆栈 :-)(但是没有寄存器,所以“纯”)(我希望你知道堆栈是什么)。当代码被 JITted 为您正在使用的计算机的机器代码时,i 可能会被放入寄存器或堆栈中。

    请注意,一般而言将值类型(或非引用类型,如果您想包括托管/非托管指针/引用)保存在堆栈上和/或在寄存器中。他们在他们得救的地方得救。例如,类的值类型成员与(在)类中保存(因此通常在堆中)。 yield 函数、异步函数、“普通”方法中但被“闭包类型”匿名函数引用的值类型通常保存在堆中的某个位置。但所有这些都是参考实现细节。

    【讨论】:

    • Desktop .NET 没有 VM,有一个 MSIL 的目标虚拟架构,但该架构没有实现。相反,JIT 编译器将 MSIL 转换为本机代码。
    • @BenVoigt 对于 VM,我的意思是虚拟机不是 VMWare,而是“虚拟架构”。
    • @BenVoigt Wiki 称他们为Process Virtual Machine
    • 我以为您的意思是 Java 虚拟机。但是.NET 没有。没有任何东西可以执行 MSIL 指令。
    • @BenVoigt 如果我没记错的话,Mono 的第一个实现会被解释。 VM 的存在与否是一个实现细节。最后,您针对这台“抽象”机器进行编程,然后,感谢微软工程师,您的代码被编译而不是被解释。
    【解决方案4】:

    据我所知,实际的堆分配引用被存储为双指针(或一些等价物),因此垃圾收集器可以移动内存,而不必影响代码中通过更新指向的指针引用的任何地方。

    【讨论】:

    • 引用(在当前实现中)不是双指针,而是直接指针。垃圾收集器在移动对象时确实会更新指针本身。
    • @Guffa 这对我来说闻起来像是糟糕的实现,因为 GC 必须跟踪项目、堆栈等的所有使用情况。
    • 无论如何它都必须这样做,才能知道哪些对象被使用,哪些没有。
    • 仅当它不使用共享指针等引用计数机制时。
    • 它没有使用引用计数。这可能会提供信息:stackoverflow.com/questions/867114/…
    猜你喜欢
    • 2014-09-08
    • 1970-01-01
    • 1970-01-01
    • 2013-11-06
    • 2013-03-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-10
    • 1970-01-01
    相关资源
    最近更新 更多