我应该让堆栈段大还是堆段大?

我正在编程一个微处理器的设计,内存非常有限,我必须在不同的功能中使用“大量”内存。 我不能有一个大的堆栈段,堆段,数据段,我必须选择哪个做大,哪个做小。 总共约32KB,

我使用大约20KB的文本段,这给了我剩下的12KB。 我需要一个4KB的缓冲区来传递不同的功能(SPI闪存扇区大小)。 应该在哪里初始化那个大缓冲区?

所以我的选择是:

1)如果我在函数的开头声明缓冲区,堆栈将需要变大

spiflash_read(...)
{
  u8 buffer[4096]; // allocated on stack 
  syscall_read_spi(buffer,...)
}

2)动态分配时,堆需要变大

spiflash_read(...)
{
  u8 *buffer = (u8*) malloc(4096); // allocated in heap
  syscall_read_spi(buffer,...)
}

3)静态分配,巨大的负面影响,不能在“SPI Library”之外使用。

static u8 buffer[4096]; // allocated in data section.

spiflash_read(...)
{
  syscall_read_spi(buffer,...)
}

我的问题是哪个是实现这种设计的最佳方式? 有人能解释推理吗?


静态分配始终是运行时安全的,因为如果内存不足,链接器将在buid时间告诉您,而不是在运行时崩溃。 但是,除非内存在执行过程中被永久需要,否则它可能是浪费的,因为分配的内存不能用于多种目的,除非您以这种方式明确地编写内存。

动态内存分配是运行时可检查的 - 如果用完堆,malloc()将返回空指针。 然而,要感谢您测试返回值,并根据需要释放内存。 动态内存块通常是4或8字节对齐的,并且存在堆管理数据开销,使得它们对于非常小的分配而言效率低下。 频繁分配和重新分配各种块大小可能导致堆碎片和浪费的内存 - 对于“永远在线”的应用程序而言,这可能是灾难性的。 如果你永远不打算释放内存,并且它会一直分配,并且你知道你需要多少,那么你可能会更好地使用静态分配。 如果你有库源,你可以修改malloc立即停止内存分配失败,以避免检查每个分配。 如果分配大小通常为几个常见大小,则固定块分配器而不是标准malloc()可能更可取。 这将更具确定性,并且您可以实施使用情况监视来帮助优化每个大小的块大小和数量。

堆栈分配是最有效的,因为它会根据需要自动获取并返回内存。 但是它也很少或没有运行时检查支持。 通常,当发生堆栈溢出时,代码将非确定性地失败 - 并且不一定在根本原因附近的任何地方。 一些链接器可以生成堆栈分析输出,该输出将通过调用树来计算最坏情况下的堆栈使用情况; 如果你有这个设施,你应该使用它,但是要记住,如果你有一个多线程系统,将会有多个栈,并且你不需要检查每个入口点的最坏情况。 此外,lonker不会分析中断堆栈的使用情况,并且您的系统可能有单独的中断堆栈或共享系统堆栈。

我将解决这个问题的方法当然不是将大数组或对象放在堆栈上,而是遵循以下过程:

  • 使用链接器堆栈分析来计算最坏情况下的堆栈使用情况,如有必要,可以为ISR提供额外的堆栈。 分配那么多堆栈。

  • 静态分配执行期间所需的所有对象。

  • 使用链接图确定剩余内存的大小,将几乎所有内容都分配给堆(链接器或链接器脚本可以自动执行该操作,但是如果必须明确设置堆大小,请留出一点未使用的空间,否则每次添加一个新的静态对象,或扩展堆栈,你将不得不调整堆大小)。 分配堆中的所有大型临时对象,并尽力释放分配的内存。
  • 如果您的库包含堆诊断函数,那么您可以在代码中使用它们来监视堆使用情况,以检查您有多疲惫。

    链接器分析“最坏情况”似乎是在实践中看到的更大 - 最糟糕的情况是我从未执行过的。 您可以预先用特定字节(比如0xEE)或模式填充堆栈,然后在进行大量测试和操作后,检查“高潮”标记并以这种方式优化堆栈。 谨慎使用此技术; 您的测试可能无法涵盖所有​​可预见的情况。


    这取决于你是否需要缓冲所有的时间。 如果你的工作的90%花费在缓冲区上,那么我会把它放在数据段中

    如果它只是暂时需要一个给定的函数,然后把它放在堆栈上。 这样做很便宜,意味着您可以重新使用该空间。 这意味着你必须有一个大堆栈

    否则把它放在堆上。

    真的,如果你是这种内存限制,你应该详细分析你的内存消耗是多少。 一旦你变得如此之小,你不能把它看作'正常',把它放在操作系统/运行时,开发。 我见过不允许进行任何动态mem分配的嵌入式开发商店; 每件事情都是预先计算并静态分配的。 虽然它们可能具有多用途内存区域(例如,一个常见的IO缓冲区)。 回到我的COBOL时代,这是你工作的唯一方式(今天的年轻人......抱怨,抱怨......)


    传统的答案是你应该操纵你的运行时间,以便你的堆栈和堆堆向对方增长。 这可以让你忽略哪一个需要“更大”,只是担心如果你没有分配足够的空间TOTAL会发生什么。

    链接地址: http://www.djcxy.com/p/82369.html

    上一篇: Should I make stack segment large or heap segment large?

    下一篇: What does “int 0x2A” mean in assembly code