VB.NET 表单变量是如何处理的

Posted

技术标签:

【中文标题】VB.NET 表单变量是如何处理的【英文标题】:How are VB.NET form variables handled 【发布时间】:2020-01-22 02:04:12 【问题描述】:

这里显示的表单类有一个处理按钮单击事件的方法。声明并初始化了一个局部值类型 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 结束子 结束类

【问题讨论】:

我认为所有方法都使用相同的堆栈。 作为一个实现细节,像整数这样的值类型存储在堆栈中。引用类型(如 foo)存储在堆中。 这是一篇可以帮助您解决问题的好文章。 c-sharpcorner.com/article/… 我很欣赏到目前为止的回复,并且那里的各种文章都很有意义,但只是在一定程度上。我仍然不确定 Windows 窗体应用程序中的工作方式。我的示例中的一些代码是在表单类中编写的。一个表单类中可能有几个子例程/方法。应用程序运行时会创建一个表单对象。该对象可能是某处堆上的引用类型 - 那么当它们开始相互调用时,哪个程序维护包含表单方法的堆栈?如果一个表单启动另一个表单,是否使用相同的堆栈? 你想通过这个提问找出什么?结局是什么? 【参考方案1】:

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

堆栈用于静态内存分配,堆用于动态内存分配,两者都存储在计算机的 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.

【讨论】:

我了解对象成员与对象内嵌存储在堆中。例如。如果表单包含在类中(而不是在方法中)声明的变量,或者引用类型 E.G.一个数组,它们将与对象数据内联存储,指针将保留在堆栈上。如果有一个“主”程序,这是有道理的。但是如果 Windows 窗体的方法(例如按钮单击事件处理程序)声明了一个局部变量怎么办?这个变量是在堆栈中维护还是与表单对象一致? form 方法的行为是否类似于 C 语言中的主程序? @Drummy 我已经更新了答案。简而言之,如果它已经在堆上,它创建的所有东西都将留在堆上,因为它不是应用程序本身的 局部变量 当涉及到我的困惑时,您已经一针见血了……既然表单是一个对象,它就在堆上。如果表单创建的所有内容都在堆上,那么在表单方法中本地声明的所有变量也都在堆上。使用 VB.NET(或 C#)中的 Windows 窗体应用程序,当我单步执行代码时,我可以看到一个调用堆栈,那么哪个程序维护它?幕后某处是否有“主程序”?不是说堆栈只包含引用吗? 这将是两者的结合。对您的类对象的引用将在堆栈上,而对象和数据本身将在堆上。它看起来类似于 i.stack.imgur.com/yZK6t.png 这开始有意义了。如果我错了,请纠正我,对于一个 VB.NET Windows 窗体应用程序,如果一个子过程(即一个表单方法)声明并分配了一个整数类型,那么数据与其余部分一起在堆上表单对象和堆栈包含对此的引用 - 这是对的吗?经过更多研究,我发现一个 VB.NET Windows 窗体应用程序有一个隐藏的“子主”。这可以用模块中的自定义 sub main 替换(您可以将其指定为启动程序)。如果自定义 sub main 声明一个整数,则数据将在堆栈上 - 对吗?

以上是关于VB.NET 表单变量是如何处理的的主要内容,如果未能解决你的问题,请参考以下文章

注销哈希,它们是如何处理的?

MIDI 文件播放一般是如何处理的?

FRP在内存方面是如何处理的?

Lua 表在内存中是如何处理的?

mern 堆栈中的路由是如何处理的?

__eq__ 在 Python 中是如何处理的以及按啥顺序处理?