【问题标题】:The Keil RTX RTOS thread stack sizeKeil RTX RTOS 线程栈大小
【发布时间】:2016-12-26 07:23:48
【问题描述】:

在 Keil RTX RTOS 配置文件中,用户可以配置默认的用户线程堆栈大小。 通常,堆栈 包含自动/局部变量。 “ZI 数据”部分包含未初始化的全局变量。

因此,如果我在 RTX 配置文件中更改用户线程堆栈大小,堆栈大小会增加,“ZI 数据”部分大小不会增加。

我测试了一下,测试结果显示如果我增加用户线程堆栈大小。 “ZI 数据”节大小会随着大小同步增加。

在我的测试程序中,有 6 个线程,每个线程有 600 字节的堆栈。我使用 Keil 构建程序,它告诉我:

代码(包括数据) RO 数据 RW 数据 ZI 数据 调试 36810 4052 1226 380 6484 518461 总计 36810 4052 1226 132 6484 518461 ELF 图像总数(压缩) 36810 4052 1226 132 0 0 ROM 总数 ==================================================== ============================== RO 总大小(代码 + RO 数据)38036 (37.14kB) 总 RW 大小(RW 数据 + ZI 数据)6864 (6.70kB) 总 ROM 大小(代码 + RO 数据 + RW 数据)38168 (37.27kB)

但如果我将每个线程堆栈大小更改为 800 字节。 Keil 显示如下:

==================================================== ============================== 代码(包括数据) RO 数据 RW 数据 ZI 数据 调试 36810 4052 1226 380 7684 518461 总计 36810 4052 1226 132 7684 518461 ELF 图像总数(压缩) 36810 4052 1226 132 0 0 ROM 总数 ==================================================== ============================== RO 总大小(代码 + RO 数据)38036 (37.14kB) 总 RW 大小(RW 数据 + ZI 数据)8064 (7.88kB) 总 ROM 大小(代码 + RO 数据 + RW 数据)38168 (37.27kB) ==================================================== ==============================

“ZI 数据”部分的大小从 6484 字节增加到 7684 字节。 7684 - 6484 = 1200 = 6 * 200。而 800 - 600 = 200。 所以我看到线程堆栈放在“ZI Data”部分。

我的问题是: 这是否意味着线程中的自动/局部变量将被放入“ZI Data”部分,当线程堆栈被放入 RAM 中的“ZI data”部分时? 如果为真,则意味着根本没有堆栈部分。根本只有“RO/RW/ZI Data”和堆部分。

这篇文章给了我不同的答案。我现在对此有点困惑。 https://developer.mbed.org/handbook/RTOS-Memory-Model

【问题讨论】:

  • “堆栈包含自动/局部变量” - 从正在运行的线程的角度来看,它是“那个”堆栈,当然。不过,从操作系统的角度来看,我看不出这些堆栈不能是静态分配变量的理由。您在这里只是提出了一个观察;具体问题是什么?

标签: stack arm rtos keil rtx


【解决方案1】:

链接器确定存在哪些内存段。默认情况下,链接器会创建一些内存段。在您的情况下,其中三个默认部分显然被命名为“RO Data”、“RW Data”和“ZI Data”。如果您没有明确指定变量应位于哪个节中,则链接器将根据变量是声明为 const、已初始化还是未初始化,将其分配给这些默认节之一。

链接器不会自动知道您正在使用 RTOS。而且它对您打算将哪些变量用作线程堆栈没有特别的了解。因此链接器不会自动为您的线程堆栈创建独立的内存部分。相反,链接器会将堆栈变量视为任何其他变量,并将它们包含在默认内存部分之一中。在您的情况下,链接器显然将线程堆栈放入 ZI Data 部分。

如果您希望链接器为您的线程堆栈创建特殊的独立内存段,那么您必须通过链接器命令文件明确告诉链接器这样做。然后您还必须指定堆栈变量应位于您的自定义部分中。有关如何执行此操作的详细信息,请参阅链接器手册。

【讨论】:

  • 谢谢。一般有一些默认段:“RO Data”、“RW Data”、“ZI Data”、“stack”、“heap”。链接器确定闪存和 RAM 存储器布局。如果将线程堆栈放入“ZI Data”中,是否意味着线程中调用的函数的所有自动变量都将在“ZI Data”部分中?那么“堆栈”部分是什么?
  • 主程序有栈。这是调用 main() 时和 RTOS 启动之前正在使用的堆栈。您的链接器命令文件可能会显式指定主堆栈的内存部分。每个线程都有自己的堆栈,与主堆栈分开。您的链接器将这些线程堆栈定位在 ZI 数据部分中。一旦 RTOS 运行,线程局部变量将在线程堆栈上创建。是的,线程局部变量将在 ZI Data 中,因为线程堆栈在 ZI Data 中。主堆栈是 RTOS 运行之前局部变量所在的位置。
  • RTOS 运行后,“主函数”将不再被调用。因此,一旦 RTOS 崩溃,主堆栈将永远不会被使用。为了节省内存,这意味着主堆栈和线程堆栈的内存空间会重叠。
  • 是的,通常 RTOS 不会返回到 main,因此在启动 RTOS 后主堆栈可能未被使用。您应该能够使主堆栈大小相对较小。从理论上讲,我想您可以安排其中一个线程堆栈超出主堆栈,以便在启动 RTOS 后重用主堆栈内存。但实际上,这似乎是一个复杂的操作,可以节省几百字的 RAM。雅尼。我建议您保持简单并将堆栈分开。从长远来看,这将使调试和维护更容易。
  • 是的,你是对的。而且我忘记了主堆栈将由 RTOS 内核使用。
【解决方案2】:

任务堆栈必须来自某个地方 - 在 RTX 中,默认情况下它们是静态分配的并且大小固定。

os_tsk_create_user() 允许调用者提供可以以任何方式分配的堆栈(静态或从堆中分配;从调用者堆栈分配是可能的,但不寻常,可能毫无意义并且肯定很危险),只要它有8 字节对齐。我发现 RTX 的自动堆栈分配几乎毫无用处,除了最琐碎的应用程序外,几乎不适合所有应用程序。

【讨论】:

    猜你喜欢
    • 2016-02-18
    • 2019-12-09
    • 2016-09-08
    • 2016-03-12
    • 2018-03-28
    • 2016-12-03
    • 2011-07-27
    • 2011-05-08
    • 1970-01-01
    相关资源
    最近更新 更多