首页 > 解决方案 > VB.NET 表单变量是如何处理的

问题描述

此处显示的表单类有一个处理按钮单击事件的方法。一个局部值类型 x 被声明和初始化。我知道在方法执行期间,它位于按钮代码的堆栈框架中。按钮代码还创建了一个名为 f 的类 foo 的实例,并调用它的方法 doSomething。我知道按钮的堆栈框架现在包含对堆上对象 f 的引用。对象 f 的 doSomething 方法声明并初始化了一个局部值类型 y。y 存储在哪里?它在同一个堆栈上吗?它在堆上,与对象 f 一致吗?或者,当 doSomething 调用 doSomethingElse 时,是否涉及不同的堆栈?大概,当一种形式实例化另一种形式时,会使用相同的机制吗?

公开课形式1
    Private Sub Button1_Click(sender As Object, e As EventArgs) 处理 Button1.Click
        将 x 调暗为整数
        x = 5
        Dim f As New foo
        f.doSomething()
    结束子
结束类

公共课 foo
    公共子 doSomething()
        Dim y As Integer
        y = 6
        调用 doSomethingElse()
    结束子

    公共子 doSomethingElse()
        将 z 调暗为整数
        z = 7
    结束子
结束类

标签: vb.netwinformsstackheap-memory

解决方案


除非您使用多线程,否则所有变量都将位于同一个堆栈中。表单将进入堆。

堆栈用于静态内存分配,堆用于动态内存分配,两者都存储在计算机的 RAM 中。

在栈上分配的变量直接存储到内存中,访问这块内存的速度非常快,而且它的分配是在程序编译的时候处理的。当一个函数或方法调用另一个函数,而另一个函数又调用另一个函数等时,所有这些函数的执行将保持挂起,直到最后一个函数返回其值。堆栈始终以 LIFO 顺序保留,最近保留的块始终是下一个要释放的块。这使得跟踪堆栈变得非常简单,从堆栈中释放一个块只不过是调整一个指针。

在堆上分配的变量在运行时分配它们的内存,访问这块内存有点慢,但堆大小仅受虚拟内存大小的限制。堆元素之间没有依赖关系,可以随时随机访问。您可以随时分配块并随时释放它。这使得在任何给定时间跟踪堆的哪些部分已分配或空闲变得更加复杂。 在此处输入图像描述

如果您确切知道在编译时需要分配多少数据并且它不太大,则可以使用堆栈。如果您不确切知道运行时需要多少数据或者需要分配大量数据,则可以使用堆。

在多线程情况下,每个线程都有自己完全独立的堆栈,但它们将共享堆。栈是线程特定的,堆是应用程序特定的。堆栈在异常处理和线程执行中很重要。

参考: http: //net-informations.com/faq/net/stack-heap.htm

更多详情

哪些对象分配在栈上,哪些对象分配在堆上?

注意:你永远不应该说“引用类型分配在堆上,而值类型分配在堆栈上”,这是一个经常重复的错误,对有经验的面试官来说是一个危险信号。

引用类型(类、接口、委托)总是在堆上分配。

当您将引用对象作为参数传递或将其分配给变量时,您实际上是在传递它的引用。引用(不是被引用的对象)既可以在堆栈上分配,也可以在堆上分配。

通过传递对对象的引用,您可以告知该对象在堆上的位置,以便您的代码可以访问它。

每次将对象作为引用传递时,都会复制引用本身。这意味着您可以更改引用以指向不同的对象,而不会影响前一个对象本身或指向它的其他引用。引用是轻量级的,并且始终是恒定大小(32 位或 64 位,具体取决于操作系统位数),因此复制它(并因此传递引用类型)被认为是便宜的。

值类型(派生自 System.ValueType,例如 int、bool、char、enum 和任何结构)可以分配在堆上或堆栈上,具体取决于它们的声明位置。

如果值类型被声明为方法内的变量,则它存储在堆栈中。如果值类型被声明为方法参数,那么它将存储在堆栈中。如果值类型被声明为类的成员,那么它会与其父级一起存储在堆中。如果值类型被声明为结构的成员,那么它将存储在存储该结构的任何位置。从 C#7.2 开始,可以将 struct 声明为 ref struct,在这种情况下,它将始终在堆栈上分配,从而防止它在引用类型中声明。

值类型的实例通过副本传递(除非与引用语义一起使用,见下文)。这意味着每次将值类型分配给变量或作为参数传递时,都会复制该值。

因为根据对象的大小复制值类型可能会变得昂贵,所以不建议将内存重的对象声明为值类型。

由于 C# 中的每种类型都派生自 System.Object,因此值类型可以分配给变量或传递给需要对象的方法。在这种情况下,该值被复制并存储在堆中,作为引用类型包装,这种操作称为装箱。

参考:https ://dev.to/tyrrrz/interview-question-heap-vs-stack-c-5aae#targetText=In%20C%23%20there%20are%20two,can%20be%20accessed%20from%20anywhere 。


推荐阅读