- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
这个问题更多是出于好奇,而不是针对任何现实世界的问题。
考虑以下代码:
void Main()
{
FAsync().Wait();
}
async Task FAsync()
{
await Task.Yield();
await FAsync();
}
在同步世界中,这最终会导致堆栈溢出。
在异步世界中,这只会消耗大量内存(我假设这与我可能松散地称为“异步堆栈”的东西有关?)
这些数据究竟是什么,它是如何保存的?
最佳答案
好问题。
堆栈是延续的具体化。简单地说,继续是关于程序接下来要做什么的信息。在传统的非异步环境中,这表示为堆栈上的返回地址;当方法返回时,它查看堆栈并分支到返回地址。堆栈上还包含有关局部变量在延续开始时的值的信息。
在异步情况下,所有信息都存储在堆上。任务包含在任务完成时调用的委托(delegate)。委托(delegate)绑定(bind)到“闭包”类的实例,该类包含任何局部变量或其他状态的字段。当然,任务本身就是堆对象。
您可能想知道:如果延续是在任务完成时调用的委托(delegate),那么完成任务的代码如何不在调用堆栈上完成在哪里执行?任务可以选择通过发布 Windows 消息来调用延续委托(delegate),并且当消息循环处理消息时,它会执行调用。因此,调用位于堆栈的“顶部”,消息循环通常位于该位置。 (用于延续的调用策略的精确细节取决于创建任务的上下文;有关详细信息,请参阅任务并行库的更高级指南。)
可以在此处找到一篇很好的介绍性文章,了解这一切是如何工作的:
https://msdn.microsoft.com/en-us/magazine/hh456403.aspx
自 Mads 撰写那篇文章以来,一些细节发生了变化,但这些想法是合理的。 (i3arnon 的回答说明了这是如何演变的;在 Mads 的文章中,一切都在堆上进行,但事实证明这在某些情况下会产生过多的垃圾。更复杂的代码生成器允许我们将一些信息保留在堆栈上。理解这种区别并不是有必要看看延续是如何在逻辑上表示的。)
这是一个有趣且有启发性的练习,让您的程序实际绘制出所有创建的委托(delegate)和任务,以及它们之间的引用是什么。试一试!
关于c# - 异步递归。我的内存到底去哪儿了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35464468/
这对你们来说可能很简单,但由于我是java新手,所以我想知道实际上什么是 接下来的部分会发生什么? if (args.length > 0) { file = args[0]; } publi
在我的 View Controller 中,我将 UITapGestureRecognizer 添加到 self.view。我在 self.view 之上添加了一个小 View 。当我点击小 View
我今天尝试从 Obj-C 开始并转到 Swift,我正在阅读文档。我试图在 Swift 中创建一个简单的 IBOutlet,但它不断给我这些错误。 View Controller 没有初始化器 req
我正在尝试使用 VIM 完成(字典和当前缓冲区),但我遇到了问题?和 !在方法名称的末尾。我能以某种方式向 vim 解释方法名称(基本上是单词)最后只能有它,而且只有一个,即 method_name
我是一名优秀的程序员,十分优秀!