RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 606824
Accepted
CSharpUser
CSharpUser
Asked:2020-12-23 05:09:55 +0000 UTC2020-12-23 05:09:55 +0000 UTC 2020-12-23 05:09:55 +0000 UTC

当一个 ValueType 被销毁时以及 GC 操作与 ValueType 的语义

  • 772

有传言说ValueType被GC删除了(即GC释放了ReferenceType和ValueType)。
但事实上,并非如此。例如我们有代码:

class A {}
class B
{
    void TestMethod()
    {
        A a = new A();
        int x = 100;
    }
}  

在TestMethod( ) 方法的上下文(范围)中,创建类型A的对象 (ReferenceType)以及变量X (ValueType)。

方法完成后,变量X被销毁,类型A的对象失去对该对象的引用,并成为从GC中移除的竞争者。

换句话说,ValueType只要被执行就存在于上下文中,相应的Stack,通过Pop()方法的类型,会自己从内存中移除这个数据,而GC不参与this ,因此ValueType工作更快(尽管这完全取决于任务)。

问题是,它总是这样工作吗?(我读过各种文章,有时他们写道,只有当堆栈堵塞时才会发生这种情况,即达到满)

当堆栈几乎已满并且其中的所有数据(例如,都是对堆上的对象的引用)时,CLR会做什么?如何以及何时删除用户结构?CLR究竟是如何决定是从堆栈中删除数据还是让它存在第 N 次!??

.net
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    user177221
    2020-12-23T07:19:28Z2020-12-23T07:19:28Z

    ValueType 类型的局部变量 [在其上没有来自匿名方法和 lambda 的闭包] 直接位于堆栈或处理器寄存器中(正如优化器所希望的那样)。

    您可以通过在调试中右键单击代码并选择 Go To Disassembly 来直接查看您的代码是如何执行的,也许这会清除一切。这是它在调试模式下的样子(关闭优化)。我在重要的地方添加了注释:

            {
    025B2E48  push        ebp     // это так называемый пролог функции
    025B2E49  mov         ebp,esp // https://en.wikipedia.org/wiki/Function_prologue 
    025B2E4B  push        edi     // суть его - сохранить текущее положение 
    025B2E4C  push        esi     // стека в "базовый указатель" - [e]bp
    025B2E4D  push        ebx  
    

    3 个寄存器的值被压入堆栈,因此它的指针现在与函数开始时的指针相差 12

    025B2E4E  sub         esp,3Ch 
    

    esp 是指向堆栈开始的指针。将它减少 3Ch 就是在堆栈上为局部变量(或其他开销)分配 3Ch(60)字节,此时它已经与 ebp 中的值相差 12,因此局部变量在地址范围内从 [ebp-13] 到 [ebp-72]。它也是 [ebp-0Dh] 到 [ebp-48h]。

    然后我们做了一堆检查并创建了一个漫长而痛苦的对象(这都是因为调试模式)。我将跳过大部分代码,它与问题无关:

    025B2E51  mov         esi,ecx  
    025B2E7C  nop  
                A a = new A();
    025B2E7D  mov         ecx,700F98h  
    025B2E82  call        024130F4  
    025B2E87  mov         dword ptr [ebp-48h],eax  
    025B2E8A  mov         ecx,dword ptr [ebp-48h]  
    025B2E8D  call        025B0D18  
    025B2E92  mov         eax,dword ptr [ebp-48h]  
    

    最后将指向创建对象的指针放入栈中(ebp包含函数调用开始时栈的位置) 025B2E95 mov dword ptr [ebp-40h],eax

    使用整数,它更容易 - 只需将所需的值推入相对 epb - 即 相对于函数执行时堆栈的开头。

                int x = 100;
    025B2E98  mov         dword ptr [ebp-44h],64h  
            }
    025B2E9F  nop  
    

    现在是重点。我们将紧随其后的值加载到堆栈指针中 025B2E4D push ebx。本质上是这样esp = ebp-0Ch

    025B2EA0  lea         esp,[ebp-0Ch]  
    025B2EA3  pop         ebx  
    025B2EA4  pop         esi  
    025B2EA5  pop         edi
    

    在下一行之后,我们得到 esp 的值等于函数开头的值。

    025B2EA6  pop         ebp
    025B2EA7  ret  
    

    由于什么,栈上的内存脱颖而出并被释放?

    它通过将堆栈指针减少到所需的值而脱颖而出。释放——通过恢复指针的旧值。局部变量的销毁或“垃圾收集”没有成本。

    这是 x86 上的标准机制,因此可以假设几乎总是如此。从函数返回时,堆栈指针的值将恢复为调用前的值。

    • 4

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何停止编写糟糕的代码?

    • 3 个回答
  • Marko Smith

    onCreateView 方法重构

    • 1 个回答
  • Marko Smith

    通用还是非通用

    • 2 个回答
  • Marko Smith

    如何访问 jQuery 中的列

    • 1 个回答
  • Marko Smith

    *.tga 文件的组重命名(3620 个)

    • 1 个回答
  • Marko Smith

    内存分配列表C#

    • 1 个回答
  • Marko Smith

    常规赛适度贪婪

    • 1 个回答
  • Marko Smith

    如何制作自己的自动完成/自动更正?

    • 1 个回答
  • Marko Smith

    选择斐波那契数列

    • 2 个回答
  • Marko Smith

    所有 API 版本中的通用权限代码

    • 2 个回答
  • Martin Hope
    jfs *(星号)和 ** 双星号在 Python 中是什么意思? 2020-11-23 05:07:40 +0000 UTC
  • Martin Hope
    hwak 哪个孩子调用了父母的静态方法?还是不可能完成的任务? 2020-11-18 16:30:55 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    Arch ArrayList 与 LinkedList 的区别? 2020-09-20 02:42:49 +0000 UTC
  • Martin Hope
    iluxa1810 哪个更正确使用:if () 或 try-catch? 2020-08-23 18:56:13 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5