堆栈使用小技巧

要写一个评测人脸识别性能的程序

把live 和 sfz 里面所有的图片的特征提取出来,两两计算相似度,这样我们就得到一个相似度矩阵。

把live 的特征和sfz 的特征都推到堆栈里面去。

BYTE* pFeature1 = new BYTE[EF_Size()];
BYTE* pFeature2 = new BYTE[EF_Size()];
EF_Extract(0, img_gallary.data, img_gallary.cols, img_gallary.rows, 3, &ptfp[max_face_index], pFeature1);
EF_Extract(0, img_live.data, img_live.cols, img_live.rows, 3, &ptfp2[0], pFeature2);		
featureDB_live.push_back(pFeature2);
featureDB_sfz.push_back(pFeature1);
for (int m = 0; m < featureDB_sfz.size(); m++)
	{
		for (int n = 0; n < featureDB_live.size();n++)
		{
			float score = 0;	
			score = EF_Compare(featureDB_live[m], featureDB_sfz[n]);
			fprintf(fp,"%f ",score);
		}
		fprintf(fp,"\n");
	}

堆栈每次都要分配内存,不然如果只申请一次,就会所有的指针都指向同一块内存,所有的结果都一样。


<think>嗯,用户现在的问题是如何在ARM单片机开发中查看堆栈使用大小。之前我们已经讨论过ARM编译后的内存组成,包括Code、RO-data、RW-data和ZI-data这些部分。用户特别提到了堆栈,结合引用中的信息,堆栈属于ZI-data区域,但编译器不会自动给出具体的使用量,所以用户需要自己确认。根据引用[1]到[4],堆栈包括栈区(存放局部变量、函数调用等)和堆区(动态内存分配)。栈空间的使用通常在编译时无法精确计算,因为函数调用深度和局部变量的大小可能变化。堆空间则取决于运行时malloc的使用情况。用户提到的引用[2]指出,编译器输出的ZI-data数据包含了堆栈的大小,但用户需要进一步确认这些空间是否足够。现在需要回答用户如何查看堆栈使用量。首先,静态分析方面,可以通过map文件来查看堆栈的分配地址和大小。引用[3]提到栈是从高地址向低地址增长,堆则相反。在map文件中找到对应的符号,比如Stack_Size和Heap_Size,通常这些值在启动文件中有定义。如果用户修改了链接脚本,这些值可能会有调整。其次,运行时监测也很重要。方法包括填充魔数,比如在栈顶之前填入特定值(如0xDEADBEEF),运行后检查这些值是否被修改。如果有部分被覆盖,说明栈溢出到了堆栈保护区。另外,可以通过调试器观察堆栈指针SP的寄存器值,对比初始栈顶地址来判断使用量。如果开启了MPU,还能设置区域边界触发故障中断,捕获溢出事件。实际项目中,用户可能需要结合使用静态和动态方法。例如,在开发初期通过map文件确保分配足够空间,并在测试阶段用魔数法或调试器观察实际使用情况。尤其在多任务环境下,每个任务的堆栈需要单独监控,避免资源竞争导致的溢出。还需要注意编译器的优化是否会影响堆栈使用。比如引用[2]提到,未使用malloc时,编译器可能优化掉堆空间。此外,ZI-data的总量包含堆栈,但用户需要区分堆和栈的具体使用情况,避免混淆。最后,用户可能需要了解如何调整堆栈大小。启动文件中通常有Stack_Size和Heap_Size的常量定义,修改后重新编译即可。比如将Stack_Size从0x400增加到0x1000以应对更大的局部数组。动态内存分配过多导致堆溢出时,可以尝试减少分配或增大Heap_Size。相关问题部分,可以围绕堆栈分配的最佳实践展开,比如如何确定合适的大小、多任务系统的堆栈隔离方法,或者常见溢出错误排查。这些能帮助用户深入理解实际开发中的调优技巧。</think> 在ARM单片机开发中,精确查看堆栈使用大小需要通过以下方法组合实现,结合编译信息和运行时监测: ### 一、静态分析方法 1. **查看链接脚本文件(.ld/.sct)** 定位`Stack_Size`和`Heap_Size`的定义值(通常定义在启动文件如`startup_stm32f4xx.s`): ```c Stack_Size EQU 0x400 ; 默认栈大小1KB Heap_Size EQU 0x200 ; 默认堆大小512B ``` 2. **解析MAP文件** 编译后生成的`.map`文件中搜索关键字段: ``` .stack 0x20001000 0x400 ; 栈起始地址和大小 .heap 0x20001400 0x200 ; 堆起始地址和大小 ``` > 注:实际占用地址需结合内存分布图验证[^2] --- ### 二、动态运行时监测 #### 方法1:栈空间魔数填充(实测验证) 1. 在启动文件初始化栈时填入特定模式(如`0xDEADBEEF`): ```assembly FillStack: LDR R0, =_estack ; 栈顶地址 LDR R1, =_sstack ; 栈底地址 Loop: CMP R0, R1 STRPL R2, [R0, #-4]! ; 向前填充魔数 BPL Loop ``` 2. 运行压力测试后,检查魔数被破坏的位置: ```c uint32_t* stack_end = (uint32_t*)&_sstack; while(*stack_end == 0xDEADBEEF) stack_end++; uint32_t used = (uint32_t)&_estack - (uint32_t)stack_end; ``` > 实际使用量 = 总栈空间 - 完整魔数区域[^3] #### 方法2:调试器实时监控 1. **查看SP寄存器值** 在调试中断时记录SP(Stack Pointer): ``` SP = 0x20000F84 // 当前栈顶 StackBase = 0x20001000 // 栈起始地址 StackUsed = StackBase - SP = 0x7C (124字节) ``` 2. **启用栈溢出检测硬件** 对于Cortex-M3/M4: ```c SCB->CCR |= SCB_CCR_STKALIGN_Msk; // 启用栈对齐检查 SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk; // 使能内存错误中断 ``` 溢出时将触发`HardFault`中断 --- ### 三、堆空间检测方法 1. **覆盖malloc/free函数** ```c static uint32_t heap_used = 0; void *my_malloc(size_t size) { void *p = __real_malloc(size); if(p) heap_used += malloc_usable_size(p); // 实际分配大小 return p; } ``` 2. **使用编译器内置统计**(ARM Compiler) ```c extern __use_no_semihosting_swi; size_t get_heap_usage(void) { __heapstats((int(*)(int, void*))heap_callback); } ``` --- ### 总结对比表 | **方法** | **精度** | **是否需要重编译** | **适用场景** | |-------------------|----------|--------------------|--------------------------| | MAP文件解析 | ★★☆ | 否 | 理论最大值预估 | | 魔数填充检测 | ★★★ | 是 | 栈空间压力测试 | | SP寄存器监控 | ★★★ | 否 | 实时调试 | | malloc重定向 | ★★★ | 是 | 堆空间精确统计 | | 硬件溢出检测 | ★★☆ | 否 | 生产环境安全防护 | > **关键结论**:栈最大用量需通过压力测试+魔数法验证;堆用量需通过定制内存分配器统计[^4] --- **
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值