Haskell 编译器如何决定是在堆上分配还是在堆栈上分配?

2024-01-10

Haskell 不具有显式内存管理功能,并且所有对象都是按值传递的,因此也没有明显的引用计数或垃圾收集。 Haskell 编译器通常如何决定是为给定变量生成在堆栈上分配的代码还是在堆上分配的代码?它是否会在堆或堆栈上为同一函数在不同的调用站点上一致地分配相同的变量?当它分配时,它如何决定何时释放内存?堆栈分配和释放是否仍以与 C 中相同的函数入口/出口模式执行?


当你调用这样的函数时

f 42 (g x y)

那么运行时行为如下:

p1 = malloc(2 * sizeof(Word))
p1[0] = &Tag_for_Int
p1[1] = 42
p2 = malloc(3 * sizeof(Word))
p2[0] = &Code_for_g_x_y
p2[1] = x
p2[2] = y
f(p1, p2)

也就是说,参数通常作为指针传递到堆上的对象,就像在 Java 中一样,但与 Java 不同的是,这些对象可能表示挂起的计算,也称为挂起的计算。thunks, 例如 (g x y/p2)在我们的例子中。如果不进行优化,这种执行模型的效率相当低,但是有一些方法可以避免其中的许多开销。

  1. GHC 做了很多内联和拆箱工作。内联消除了函数调用开销,并且通常可以实现进一步的优化。拆箱意味着改变调用约定,在上面的例子中我们可以通过42直接而不是创建堆对象p1.

  2. 严格性分析可以确定是否保证对某个参数进行评估。在这种情况下,我们不需要创建 thunk,而是完全评估表达式,然后将最终结果作为参数传递。

  3. 小对象(目前只有8bitChars and Ints) 被缓存。 也就是说,不是为每个对象分配一个新指针,而是返回一个指向缓存对象的指针。 即使该对象最初是在堆上分配的,垃圾收集器稍后也会删除它们的重复项(只有小Ints and Chars)。由于对象是不可变的,所以这是安全的。

  4. 有限的逃逸分析。对于本地函数,一些参数可以在堆栈上传递,因为在外部函数返回时它们已知为死代码。

Edit:有关(更多)更多信息,请参阅“在库存硬件上实现惰性函数语言:无脊柱无标签 G 机” http://research.microsoft.com/apps/pubs/default.aspx?id=67083。本文使用“push/enter”作为调用约定。较新版本的 GHC 使用“eval/apply”调用约定。有关该转换的权衡和原因的讨论,请参阅“如何快速咖喱:push/enter 与 eval/apply” http://research.microsoft.com/en-us/um/people/simonpj/papers/eval-apply/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Haskell 编译器如何决定是在堆上分配还是在堆栈上分配? 的相关文章

随机推荐

  • 如何防止 json_encode() 删除含有无效字符的字符串

    有没有办法保留json encode 从返回null对于包含无效 非 UTF 8 字符的字符串 在复杂的系统中进行调试可能会很痛苦 实际看到无效字符或者至少将其省略会更合适 就目前情况而言 json encode 会默默地丢弃整个字符串 示
  • Ionic 2:Cordova 不可用。确保包含 cordova.js 或在设备/模拟器中运行(在模拟器中运行)

    我刚刚设置了我的第一个 ionic 2 应用程序 我相当广泛地使用了 ionic 1 我正在尝试使用离子原生相机 http ionicframework com docs v2 native camerapreview 预览插件 设置非常简
  • 将 Maven 项目转换为 Eclipse 的动态 Web 项目

    使用 Maven 创建一个 Web 项目 mvn archetype generate DgroupId com trial DartifactId message DarchetypeArtifactId maven archetype
  • 如何接收短信并根据短信内容拨打电话提醒某人?

    因此 我尝试接收传入的短信 并根据短信的内容拨打带有特定录音的电话 例如 我有一个带调制解调器的门传感器 可以在门打开或关闭时向我的 twilio 发送文本 如果 Twilio 收到 门已打开 文本 则 twilio 将拨打我的手机并播放显
  • 如何创建所有数字组合的n维数组?

    我想创建一个函数AllCombnations d maxValue 这将创建一个包含从 0 到 的所有数字组合的 d 维数组maxValue 例如 在 3D 空间中创建所有数字组合 从 0 到maxValue可能是这样的 for int i
  • 挽救模块内特定类型的所有错误

    我有一个模块 在其中执行项目的所有加密 解密任务 我想抓住任何OpenSSL Cipher CipherError该模块中发生的异常以便我可以处理它们 是否可以做类似的事情 rescue from OpenSSL Cipher Cipher
  • Symfony 4 Composer 脚本

    我刚刚安装了 Symfony 4 项目并在中找到了此部分composer json scripts auto scripts cache clear symfony cmd assets install PUBLIC DIR symfony
  • 如何获得没有标签的地图?

    我想要一张有路网的地图 我只需要一张图片 但没有标签 地图上的文字 我尝试从 Google API 获取这样的地图并想 element geometry works 但是 例如 依然充满文字 如何获取没有文字标签的路网图 静态图片也可以 任
  • 如何打开两个Javafx窗口?

    我正在使用 javafx 想在按钮的 setOnAction 中编写代码来关闭 javafx1 类并运行 javafx2 类 但我看到错误 应用程序启动不得被调用多次 我怎样才能解决这个问题 This code is in the clas
  • 这段 JavaScript 代码是什么意思?

    var myval function 我不明白 function 含义甚至其他代码 你所拥有的是 自调用匿名函数 您首先通过在函数本身周围添加括号来创建函数表达式 只是为了写 function 在这种情况下不起作用 因为这将定义一个函数声明
  • Magento 扩展 404 错误

    我很难过 我有一个自定义扩展 可以在 Mac Leopard 本地完美运行 但是在将实时推送到主机 Centos Linux 后 当我尝试调用前端路由器时 出现 Magento 404 错误 例如这个网址 domain shop index
  • PHP 如何获取带有类和名称空间路径的方法名称作为字符串?

    我真的很讨厌写这个问题 因为我是一种 研究人员 而且 我总是能找到我正在寻找的东西 但这一个让我很烦恼 我在任何地方都找不到答案 所以 事情是这样的 正如标题所示 我需要获取一个方法名称 其中尾随类和命名空间路径作为字符串 我的意思是这样的
  • 关于android加速度计onSensorChanged的信息

    我正在尝试在android平台上编写一个体感游戏 我将整个运动检测算法包含到 onSensorChanged 函数中 问题在于该函数根据输入执行不同的时间 我对函数如何执行和调用有一些疑问 1 如果我的函数执行很长时间 并且发生了 2 个
  • 使用 Julia 中的 Images 导出图像

    假设我有一个m by n by 3的数组Uint8它表示一个图像 其中假定使用 RGB 色彩空间 我想使用以下命令将其导出为每像素 24 位 PNG 图像Images包裹 我怎样才能做到这一点 我天真地尝试申请imwrite到随机生成的原始
  • 附加 pandas 数据框自动转换为 float 但需要 int

    如何让 pandas 附加一个整数并保留整数数据类型 我意识到我可以在输入数据后将 df test astype int 添加到整个列 但如果我可以在附加数据时执行此操作 那么这似乎是一个更好的方法 这是一个示例 from bitstrin
  • 即使包含当前脚本,也要获取当前脚本的 URL?

    我有一个 PHP 脚本 需要知道它的 URL 即使它包含在另一个脚本中 我试过了 SERVER REQUEST URI 但这不会将 URI 返回到我的脚本 而是将 URI 返回到包括脚本 我也尝试过 dirname FILE 但我似乎无法将
  • 通过 gcloud 命令行工具触发特定 git 提交的构建

    我遇到的所有示例均采用以下格式 gcloud container builds submit config cloudbuild yaml 手册页内容如下 SOURCE The source directory on local disk
  • 自定义按钮的核心图形与图像

    我什么时候应该使用核心图形而不是图像来制作自定义 UIButton 核心显卡速度更快吗 除了分辨率独立之外 还有其他主要好处吗 核心显卡的优点 绘制按钮的代码可能比图像文件小 允许动态修改 轻微更改 而无需添加完整的第二个图像 正如您提到的
  • 在 Rust 中多次使用同一个迭代器

    编者注 此代码示例来自 1 0 之前的 Rust 版本 当时实现了许多迭代器Copy 此代码的更新版本会产生不同的错误 但答案仍然包含有价值的信息 我正在尝试编写一个函数来将字符串拆分为字母和数字块 例如 test123test 会变成 t
  • Haskell 编译器如何决定是在堆上分配还是在堆栈上分配?

    Haskell 不具有显式内存管理功能 并且所有对象都是按值传递的 因此也没有明显的引用计数或垃圾收集 Haskell 编译器通常如何决定是为给定变量生成在堆栈上分配的代码还是在堆上分配的代码 它是否会在堆或堆栈上为同一函数在不同的调用站点