动态设置线程栈大小

本文介绍了一种通过调整Java线程栈大小来优化递归调用的方法,避免堆栈溢出。通过修改Thread构造函数中的栈大小参数,可以在不增加所有线程开销的情况下提高递归深度。

在做一些算法开发的时候 我们经常在使用递归的时候 经常会遇到堆栈溢出,通常我们会想到设置jvm的参数来增加线程栈大小,但是这种会造成每个线程的栈都变的很大,此处介绍一个在代码中扩大线程栈大小。



 
  1. public Thread(ThreadGroup group, Runnable target, String name,
  2. long stackSize)

Thread类提供一个构造方法 可以指定线程栈大小


 
  1. public static void main(String[] args) {
  2. new Thread( null, new Runnable() {
  3. int dep = 0;
  4. @Override
  5. public void run() {
  6. try {
  7. d();
  8. } catch (Throwable e) {
  9. }
  10. System.out.println(dep);
  11. }
  12. void d() {
  13. dep++;
  14. d();
  15. }
  16. }).start();
  17. }


使用默认的栈我们的程序的深度大约为2w左右


 
  1. public static void main(String[] args) {
  2. new Thread( null, new Runnable() {
  3. int dep = 0;
  4. @Override
  5. public void run() {
  6. try {
  7. d();
  8. } catch (Throwable e) {
  9. }
  10. System.out.println(dep);
  11. }
  12. void d() {
  13. dep++;
  14. d();
  15. }
  16. }, "thread-1", 1024 1024 30).start();
  17. }


将栈大小设置为30M  此时 栈的深度可以达到650w左右



### 3.1 线程大小的查看与设置 在 ESP32-S3 上,线程(任务)的大小在创建任务时通过参数指定,通常以字节为单位。例如,在使用 `xTaskCreate` 或 `xTaskCreatePinnedToCore` 创建任务时,大小作为第三个参数传入: ```c xTaskCreate(task_function, "task_name", STACK_SIZE, NULL, TASK_PRIORITY, NULL); ``` 其中 `STACK_SIZE` 即为该任务大小(单位为字节)[^3]。若需查看当前任务的使用情况,可以使用 FreeRTOS 提供的 `uxTaskGetStackHighWaterMark` 函数获取任务运行过程中使用的最低剩余值,表示的最大使用深度: ```c UBaseType_t stack_free = uxTaskGetStackHighWaterMark(NULL); ESP_LOGI(TAG, "Current task stack high water mark: %u bytes", stack_free); ``` 该值越小,说明任务的使用越接近极限,存在溢出的风险。 ### 3.2 大小的合理设置 选择合适的大小需要综合考虑任务的函数调用深度、局部变量大小以及系统资源限制。ESP-IDF 中默认的大小通常为 2KB 至 4KB,但在实际开发中,例如 UI 任务或涉及大量网络通信的任务,可能需要更大的空间。例如,在创建 LCD 更新任务时,若大小设置为 `8192 * 4`,可能导致堆内存溢出并返回错误码 `-1`: ```c BaseType_t status = xTaskCreate(lcd_update_task, "lcd", 8192 * 4, parameter, 1, &lcd_task); if (status != pdPASS) { ESP_LOGE(UI_TAG, "xTaskCreate lcd_update_task err"); } ``` 这通常表明 FreeRTOS 的堆内存不足,需检查 `esp_get_free_heap_size()` 和 `xPortGetFreeHeapSize()` 的返回值,确保有足够内存用于任务创建[^2]。 ### 3.3 多核任务中的管理 在双核架构下,任务可以绑定到特定的 CPU 核心运行。例如,使用 `xTaskCreatePinnedToCore` 创建任务时,可指定核心编号(0 或 1),同时传入大小: ```c xTaskCreatePinnedToCore(taskOnCore0, "Core0_Task", 10000, NULL, 1, NULL, 0); xTaskCreatePinnedToCore(taskOnCore1, "Core1_Task", 10000, NULL, 1, NULL, 1); ``` 此处大小设置为 `10000` 字节,适用于较复杂任务的执行,如传感器数据处理、网络通信等。若任务过小,可能导致溢出,表现为程序崩溃或不可预测行为。 ### 3.4 大小配置建议 在嵌入式项目中,大小的配置应遵循以下原则: - **保守估计**:对任务函数调用层级、局部变量大小进行估算,适当预留安全空间。 - **使用工具辅助**:利用 `menuconfig` 中的 `CONFIG_FREERTOS_CHECK_STACKOVERFLOW` 选项启用溢出检测,帮助发现潜在问题。 - **动态调整**:在调试阶段使用 `uxTaskGetStackHighWaterMark` 监控使用情况,逐步优化大小[^2]。 --- ###
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值