diff --git a/docs/en/api-guides/performance/ram-usage.rst b/docs/en/api-guides/performance/ram-usage.rst index d5fe392b9a..9c007361f1 100644 --- a/docs/en/api-guides/performance/ram-usage.rst +++ b/docs/en/api-guides/performance/ram-usage.rst @@ -60,7 +60,7 @@ Configuration Options for Stack Overflow Detection Hardware Stack Guard ~~~~~~~~~~~~~~~~~~~~ - The Hardware Stack Guard is a reliable method for detecting stack overflow. This method uses the hardware's assist-debug module to monitor the CPU's stack pointer register. A panic is immediately triggered if the stack pointer register goes beyond the bounds of the current stack (see :ref:`Hardware-Stack-Guard` for more details). The Hardware Stack Guard can be enabled via the :ref:`CONFIG_ESP_SYSTEM_HW_STACK_GUARD` option. + The Hardware Stack Guard is a reliable method for detecting stack overflow. This method uses the hardware's Debug Assistant module to monitor the CPU's stack pointer register. A panic is immediately triggered if the stack pointer register goes beyond the bounds of the current stack (see :ref:`Hardware-Stack-Guard` for more details). The Hardware Stack Guard can be enabled via the :ref:`CONFIG_ESP_SYSTEM_HW_STACK_GUARD` option. End of Stack Watchpoint ~~~~~~~~~~~~~~~~~~~~~~~ @@ -72,18 +72,13 @@ Stack Canary Bytes The Stack Canary Bytes feature adds a set of magic bytes at the end of each task's stack, and checks if those magic bytes have changed on every context switch. If those magic bytes are overwritten, a panic is triggered. Stack Canary Bytes can be enabled via the :ref:`CONFIG_FREERTOS_CHECK_STACKOVERFLOW` option. -FreeRTOS Check Stack Overflow -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -There is a less effective alternative, see :ref:`CONFIG_FREERTOS_CHECK_STACKOVERFLOW` docs for details. - .. note:: When using the End of Stack Watchpoint or Stack Canary Bytes, it is possible that a stack pointer skips over the watchpoint or canary bytes on a stack overflow and corrupts another region of RAM instead. Thus, these methods cannot detect all stack overflows. .. only:: SOC_ASSIST_DEBUG_SUPPORTED - Recomended and default option is :ref:`CONFIG_ESP_SYSTEM_HW_STACK_GUARD` which avoids this disadvantage. + Recommended and default option is :ref:`CONFIG_ESP_SYSTEM_HW_STACK_GUARD` which avoids this disadvantage. Run-time Methods to Determine Stack Size ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/zh_CN/api-guides/performance/ram-usage.rst b/docs/zh_CN/api-guides/performance/ram-usage.rst index 1c912bac76..f9aa80db62 100644 --- a/docs/zh_CN/api-guides/performance/ram-usage.rst +++ b/docs/zh_CN/api-guides/performance/ram-usage.rst @@ -45,24 +45,54 @@ ESP-IDF 包含一系列堆 API,可以在运行时测量空闲堆内存,请 .. _optimize-stack-sizes: -栈内存大小优化 +确定栈内存大小 -------------------- 在 FreeRTOS 操作系统中,任务栈通常从堆中分配。每个任务的栈大小固定,且会作为参数传递给 :cpp:func:`xTaskCreate`。每个任务可用的栈内存不得超过为其分配的栈内存大小,否则将导致栈内存溢出或堆内存损坏,使原本可用的程序崩溃。 因此,确定每个任务栈内存的最佳大小、最小化每个任务栈内存大小、以及最小化任务栈内存的整体数量,都可以大幅减少 RAM 的使用。 -要确定特定任务栈内存的最佳大小,请执行以下操作: +栈溢出检测的配置选项 +^^^^^^^^^^^^^^^^^^^^ -- 程序运行时,如你认为某任务有未使用的栈内存,可通过其任务句柄调用 :cpp:func:`uxTaskGetStackHighWaterMark`。该函数将以字节为单位,返回任务中生命周期最短的空闲栈内存。 +.. only:: SOC_ASSIST_DEBUG_SUPPORTED + + 硬件栈保护 + ~~~~~~~~~~~~ + + 硬件栈保护是一种检测栈溢出的可靠方法,通过硬件的辅助调试模块来监视 CPU 的栈指针寄存器。如果栈指针寄存器超出了当前栈的边界,则立即触发紧急情况提示(更多详细信息,请参阅 :ref:`Hardware-Stack-Guard`)。可以通过 :ref:`CONFIG_ESP_SYSTEM_HW_STACK_GUARD` 选项启用硬件栈保护。 + +栈末尾监视点 +~~~~~~~~~~~~~~ + +栈末尾监视点将 CPU 监视点放置在当前栈的末尾。如果该字被覆盖(例如栈溢出),则会立即触发紧急情况提示。在未使用调试器的监视点时,可以设置 :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` 选项,启用栈末尾监视点功能。 + +栈金丝雀字节 +~~~~~~~~~~~~~~ + +栈金丝雀字节功能在每个任务的栈末尾添加一组魔术字节,并在每次上下文切换时检查这些字节是否已更改。如果这些魔术字节被覆盖,则会触发紧急情况提示。可以通过 :ref:`CONFIG_FREERTOS_CHECK_STACKOVERFLOW` 选项启用栈金丝雀字节功能。 + +.. note:: + + 使用栈末尾监视点或栈金丝雀字节时,栈指针可能在栈溢出时跳过监视点或金丝雀字节,损坏 RAM 的其他区域。因此,上述方法并不能检测所有的栈溢出。 + + .. only:: SOC_ASSIST_DEBUG_SUPPORTED + + 推荐启用默认选项 :ref:`CONFIG_ESP_SYSTEM_HW_STACK_GUARD`,避免这个缺点。 + +任务运行时确定栈内存大小的方法 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- 调用 :cpp:func:`uxTaskGetStackHighWaterMark` 会返回任务整个生命周期中空闲栈内存的最小值,从而较好地显示出任务未使用的栈内存量。 - 从任务本身内部调用 :cpp:func:`uxTaskGetStackHighWaterMark` 是调用该函数最容易的方式:在任务达到其栈内存使用峰值后,调用 ``uxTaskGetStackHighWaterMark(NULL)`` 获取当前任务的高水位标记,换言之,如果有主循环,请多次执行主循环来覆盖各种状态,随后调用 :cpp:func:`uxTaskGetStackHighWaterMark`。 - 通常可以用任务的栈内存总大小减去调用 :cpp:func:`uxTaskGetStackHighWaterMark` 的返回值,计算任务实际使用的栈内存大小,但应留出一定的安全余量,应对运行时栈内存使用量的小幅意外增长。 -- 程序运行时,调用 :cpp:func:`uxTaskGetSystemState` 获取系统中所有任务的摘要,包括各栈内存的高水位标记值。 -- 在未使用调试器的监视点时,可以设置 :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` 选项。启用此选项时,系统会使用一个观察点,监视每个任务栈的最后一个字节。如果有新的数据覆盖了该字节(例如发生栈溢出),将立即触发 panic。相比默认 :ref:`CONFIG_FREERTOS_CHECK_STACKOVERFLOW` 选项的 ``Check using canary bytes``,这种方式更可靠,因其能够立即触发 panic,而不是在下一次 RTOS 上下文切换时触发。然而,两种选项都存在缺点,有时栈指针可能会跳过监视点或 canary 字节,损坏 RAM 的其他区域。 +- 调用 :cpp:func:`uxTaskGetSystemState` 来获取系统中所有任务的摘要,包括各栈内存的高水位标记值。 -要减少特定任务栈内存大小,请执行以下操作: + +减少栈内存大小 +-------------- - 避免占用过多栈内存的函数。字符串格式化函数(如 ``printf()``)会使用大量栈内存,如果任务不调用这类函数,通常可以减小其占用的栈内存。 @@ -71,12 +101,13 @@ ESP-IDF 包含一系列堆 API,可以在运行时测量空闲堆内存,请 - 避免在栈上分配大型变量。在 C 语言声明的默认作用域中,任何分配为自动变量的大型结构体或数组都会占用栈内存。要优化这些变量占用的栈内存大小,可以使用静态分配,或仅在需要时从堆中动态分配。 - 避免调用深度递归函数。尽管调用单个递归函数并不一定会占用大量栈内存,但若每个函数都包含大量基于栈的变量,那么调用这些函数的开销将会很高。 -要减少任务的整体数量,请执行以下操作: +减少任务数量 +^^^^^^^^^^^^ -- 合并任务。如果从未创建某个特定任务,就不会分配该任务的栈内存,从而极大减少 RAM 使用。如果某些任务可以与另一个任务合并,通常可以将不必要的任务删除。在应用程序中,如果满足以下条件,通常可以合并或删除任务: +合并任务。如果从未创建某个特定任务,就不会分配该任务的栈内存,从而极大减少 RAM 使用。如果某些任务可以与另一个任务合并,通常可以将不必要的任务删除。在应用程序中,如果满足以下条件,通常可以合并或删除任务: - - 任务所执行的内容可以按顺序分解为多个函数调用。 - - 任务所执行的内容可以分解为较小的工作,这些工作可以通过 FreeRTOS 队列或类似机制串行化,并由工作任务执行。 +- 任务所执行的内容可以按顺序分解为多个函数调用。 +- 任务所执行的内容可以分解为较小的工作,这些工作可以通过 FreeRTOS 队列或类似机制串行化,并由工作任务执行。 内部任务栈内存大小 ^^^^^^^^^^^^^^^^^^^^