0

所以我有下面的代码。如果我直接调用signKey()loopTask中的函数,空闲堆是稳定的。但是,如果我使用该函数来创建任务xTaskCreate(),则可用堆总是在减少。我错过了什么吗?

这是使用直接调用在串行监视器上的输出:

FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312
FreeHeap: 358312

这是使用任务的串行监视器上的输出:

FreeHeap: 338364
FreeHeap: 337776
FreeHeap: 337228
FreeHeap: 336632
FreeHeap: 336080
FreeHeap: 335508
FreeHeap: 334960
FreeHeap: 334372
FreeHeap: 333812
FreeHeap: 333220
FreeHeap: 332672
FreeHeap: 332108
FreeHeap: 331552
FreeHeap: 330964
FreeHeap: 330416
FreeHeap: 329856
FreeHeap: 329304
FreeHeap: 328716
FreeHeap: 328152

这是代码:

#include "mbedtls/pk.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"

static String privateKey = "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCID48Vp/9ydCMU\nzZ4n4iQ6pzr6eK+VCL7LcpY8j/tBwLWk3jZ3ETmMm6Ua4MhUMc3ABN84uz0RgDi9\nb4RhOUy2SVbvfm5WZhlvpPmDD0yeTgWEyM3h3fBYPnRzMn/6KjsmCUgcfTWjdA+C\nj9vTL41j7bVCkU0/glBh5Rk3rKeImeX/lf4KfstguvJ+OlznCn039+tDlsCNrRgw\ni+L2AeI4UDZEDGWYRbONzU2WgJ11fr9J+Y6rSCwommDcxhdTtdlorZj2CFEtxRp5\nFCDm6Tvu0+aur8zpuhC+NFUWmYEHxztz18X1I4Pcy5cJpuqKL5t/Hxy5Yu7y32Ek\nE8DZv1DFAgMBAAECggEBAIBF+uW13tSuvSwttf9v6iwJ4UamZRKijg4MV6t9KqoQ\n3q8yeDLE4Ha5fmzaosMNuSZg8XnwvGA1fEjMTAfFF5d7iSR9E9UMqMpixIFU+Sz9\n7aIEFmXs8VygdPTuFU1qZx0y/vMs8FbLYpv6uIpfeHNPdeXuSt+nIdVJQf8FHWVg\nH7EJHJPCh0SoQZHQhV0M/n7K6iacXdC2k4AW2f2KtwPBOV19S+4Ymq7S6ycIyghd\nmMzMhWLgZYoPycMYQRDErEZOSHQHs+BqvKYqp/UVJNKAVihiqYXHmT8hnWMaaj8d\nQzVmcsq7dZO7vX+0Zfjd+krj9gbpCG30ESeNOx5sLAECgYEA0wDiGFyFAu6fVhm5\np4pHhGhFK765Ys3b5bapEgD1uN92BttPat2Qj11TKGdAERa8X0uuBB8McGcWUcvV\nFUIKYE0qj4k/oo7OEw5KmrQVlQLsWv4rls8XTEJcUnoq2lCTXZEfuwEJFBkk4Bkb\nhioZE3CU0cV/Jg78vl37SJZbE4ECgYEApRNmRPCDWH8Jeo7OSqgee8Qy46R+JpBb\nmaaQ9dCO8pp5MYLQSA4C4BeHEpKq4v6C3HL7gf+Z6N/6/WU1X1bqDtXPdito5Zxc\nQ0Sa6URIPu7/txNU4Nc4GOfB6nG0/bxiQRDkxf7Kwk2E8xpmoCAQwDhg58Y1k61q\nO/iTjIJOj0UCgYEAo7yDtrPU47mYG5BK6R/871qakp+l7G4ivddIy5fDFnsRc7Cr\nqBnXG+knpqq4pIooEyr/FmOhm3fjcgXijGR6+M/ovwmaP+LhNxhX/ETSmpdyIgoq\neRSq15qHWdlDd7YfJPSA0vSyvs3kN6JEIZB5dQRf94hyam4m4vK7FFDYzAECgYEA\nlBiva7ILZF20d0ufL8NcddUzgp+UvaxNQa/55U7SsDx99jlR+xL26WyyNat3vGZx\nqK1PjvVtc0tete8SzxH+soiHs5CGb1i0PXVTNWuZFTz+FZU2VPFA1rc1dcvFgM59\np7osRKWt6lv5ptBMueOKo6jw538fmfm+kUcVuL0/FbECgYBx9ADNvyUaPq/3rQEa\n4Nzp+yyBL8r7iguLvI8EAYbCil9lACL+xXtScQ7mCY8EW8D8w/0cqA3Wjamb5ntS\n4T9Id1Iqq6MvzgJlTjNAYrsgoEC+fmU8iPnHNjxXrf74j4Mlh9pm5j6yeYsHQnMI\nv60FP7rcRiL2XnDJ5/ev/BWXaQ==\n-----END PRIVATE KEY-----";
static bool isTask = false;
static bool printSerial = false;

const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";

static String base64_encode(const uint8_t *bytesToEncode, uint16_t len) {
  String ret;
  int i = 0;
  int j = 0;
  unsigned char char_array_3[3];
  unsigned char char_array_4[4];

  while (len--) {
    char_array_3[i++] = *(bytesToEncode++);
    if (i == 3) {
      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
      char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
      char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
      char_array_4[3] = char_array_3[2] & 0x3f;
      for (i = 0; (i < 4); i++) {
        ret += base64_chars[char_array_4[i]];
      }
      i = 0;
    }
  }

  if (i) {
    for (j = i; j < 3; j++) {
      char_array_3[j] = '\0';
    }
    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
    char_array_4[3] = char_array_3[2] & 0x3f;
    for (j = 0; (j < i + 1); j++) {
      ret += base64_chars[char_array_4[j]];
    }
  }
  return ret;
}

static String base64_encode(String str) {
  return base64_encode((const unsigned char *) str.c_str(), str.length());
}

uint8_t buffer[2000];
static void signKey(void *parameter) {
  String header = "{\"typ\":\"JWT\",\"alg\":\"RS256\"}";
  String payload = "{\"payload\":\"my-payload\"}";

  String content = base64_encode(header) + "." + base64_encode(payload);

  mbedtls_pk_context pk_context;
  mbedtls_pk_init(&pk_context);
  int rc = mbedtls_pk_parse_key(&pk_context, (uint8_t*)privateKey.c_str(), privateKey.length() + 1, NULL, 0);
  if (rc != 0) {
    mbedtls_pk_free(&pk_context);
    if (printSerial)Serial.println("Failed to parse private key (err_code: 0x" + String(rc, HEX) + ")");
    if (isTask)vTaskDelete(NULL);
  }

  mbedtls_entropy_context entropy;
  mbedtls_entropy_init(&entropy);
  mbedtls_ctr_drbg_context ctr_drbg;
  mbedtls_ctr_drbg_init(&ctr_drbg);
  const char* pers = "firebase-jwt";
  mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers));

  uint8_t digest[32];
  rc = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), (uint8_t*)content.c_str(), content.length(), digest);
  if (rc != 0) {
    mbedtls_pk_free(&pk_context);
    mbedtls_entropy_free(&entropy);
    mbedtls_ctr_drbg_free(&ctr_drbg);
    if (printSerial)Serial.println("Failed to digest content (err_code: 0x" + String(rc, HEX) + ")");
    if (isTask)vTaskDelete(NULL);
  }

  size_t retSize;
  rc = mbedtls_pk_sign(&pk_context, MBEDTLS_MD_SHA256, digest, sizeof(digest), buffer, &retSize, mbedtls_ctr_drbg_random, &ctr_drbg);
  if (rc != 0) {
    mbedtls_pk_free(&pk_context);
    mbedtls_entropy_free(&entropy);
    mbedtls_ctr_drbg_free(&ctr_drbg);
    if (printSerial)Serial.println("Failed to sign content (err_code: 0x" + String(rc, HEX) + ")");
    if (isTask)vTaskDelete(NULL);
  }

  String signature = base64_encode(buffer, retSize);
  if (printSerial)Serial.println(signature);
  mbedtls_pk_free(&pk_context);
  mbedtls_entropy_free(&entropy);
  mbedtls_ctr_drbg_free(&ctr_drbg);
  if (isTask)vTaskDelete(NULL);
}

void tryTask() {
  isTask = true;
  xTaskCreate(signKey, "signKey", 4096, NULL, 1, NULL);
}

void tryDirectCall() {
  isTask = false;
  signKey(NULL);
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  tryTask();
  //tryDirectCall();
  Serial.println("FreeHeap: " + String(ESP.getFreeHeap()));
  delay(5000);
}

更新: 我尝试在 上创建任务setup()并使任务不断循环,没有发生减少的空闲堆!所以这个问题只存在于我动态创建和删除任务时。为什么会发生这种情况?

4

1 回答 1

2

ESP32 有两种类型的内存——数据和指令。Arduino 包装器返回了对自由堆的相当自由的解释——查询的电缆MALLOC_CAP_INTERNAL可能包括这两种类型。所以它可能只是代码缓存被一次性线程的垃圾填充。

那,或者你在泄漏。无论如何,单次使用的线程在微观上并不是一种常用的做法——它们使一切变得更加困难,包括这样的分析。标准方法是在启动时创建一个永久的 FreeRTOS 任务,并在它必须做某事时通过消息队列传递它的工作项。我可以推荐FreeRTOS 教程作为一个很好的资源。

于 2021-01-08T16:35:31.487 回答