Android平台TFLite C++调用Invoke()触发段错误问题求助
问题
开发基于TFLite的Android C++应用,自行编译.so库失败后使用网上预编译库,测试项目中运行正常,但集成到实际项目后调用this->m_interpreter->Invoke()时触发段错误。项目采用双线程架构:一个线程获取输入,另一个线程调用TFLite;构造函数仅执行一次,run函数每帧调用,已确认输入参数、尺寸及初始化均正常。
相关代码
tflite.cpp
#include "tflite.hpp" tflite::tflite(uint8_t *data, size_t size) { try { lib_tflite::ErrorReporter* error_reporter; this->m_env = lib_tflite::FlatBufferModel::BuildFromBuffer((const char *)data, size, error_reporter); lib_tflite::ops::builtin::BuiltinOpResolver resolver; lib_tflite::InterpreterBuilder(*this->m_env, resolver)(&m_interpreter); if (m_interpreter->AllocateTensors() != kTfLiteOk) { throw std::runtime_error("Failed to allocate tensor"); } m_interpreter->SetNumThreads(2); this->m_input_node_count = m_interpreter->inputs().size(); this->m_output_node_count = m_interpreter->outputs().size(); for (size_t idx = 0; idx < this->m_input_node_count; ++idx) { int input = m_interpreter->inputs()[idx]; auto height = m_interpreter->tensor(input)->dims->data[1]; auto width = m_interpreter->tensor(input)->dims->data[2]; auto channels = m_interpreter->tensor(input)->dims->data[3]; std::vector<int> res = {(int)this->m_input_node_count, channels, width, height}; this->m_inputDims.push_back(res); const TfLiteTensor* input_tensor = m_interpreter->input_tensor(idx); size_t element_count = 1; for (int i = 0; i < input_tensor->dims->size; i++) { element_count *= input_tensor->dims->data[i]; } this->m_input_elem_size.push_back(element_count); } for (size_t idx = 0; idx < this->m_output_node_count; ++idx) { int output = m_interpreter->outputs()[idx]; auto height = m_interpreter->tensor(output)->dims->data[1]; auto width = m_interpreter->tensor(output)->dims->data[2]; auto channels = m_interpreter->tensor(output)->dims->data[3]; std::vector<int> res = {(int)this->m_output_node_count, channels, width, height}; this->m_outputDims.push_back(res); const TfLiteTensor* output_tensor = m_interpreter->output_tensor(idx); int element_count = 1; for (int i = 0; i < output_tensor->dims->size; i++) { element_count *= output_tensor->dims->data[i]; } this->m_output_elem_size.push_back(element_count); } for (size_t idx = 0; idx < this->m_input_node_count; ++idx) { this->m_input_buffer.emplace_back(this->m_input_elem_size[idx], 0 ); } for (size_t idx = 0; idx < this->m_output_node_count; ++idx) { this->m_output_buffer.emplace_back(this->m_output_elem_size[idx], 0 ); } } bool tflite::run(std::vector<float> &t_out_buffer, std::vector<float> &t_cls_buffer, std::vector<float> &t_buffer, size_t region_size) noexcept { for(size_t idx = 0; idx < this->m_input_node_count; idx++) { float* data_ptr = m_interpreter->typed_input_tensor<float>(idx); memcpy(data_ptr, t_buffer.data(), this->m_input_elem_size[idx]); } // This is where it fails if (kTfLiteOk != this->m_interpreter->Invoke()) { log_error("Failed to invoke\n"); return false; } for(size_t idx = 0; idx < this->m_output_node_count; idx++) { float* output = this->m_interpreter->typed_output_tensor<float>(idx); this->m_output_buffer[idx] = std::vector<float> (output, output + this->m_output_elem_size[idx]); } t_cls_buffer = this->m_output_buffer[0]; t_out_buffer = m_output_buffer[1]; } /* end_of_file */
tflite.hpp
#ifndef TFLITE_DRIVER_HPP #define TFLITE_DRIVER_HPP #include <memory> #include "tensorflow/lite/interpreter.h" #include "tensorflow/lite/kernels/register.h" #include "tensorflow/lite/model.h" #include "tensorflow/lite/optional_debug_tools.h" namespace lib_tflite = ::tflite; class tflite { public: tflite() = delete; virtual ~tflite() noexcept = default; tflite(tflite &&) = delete; tflite & operator=(tflite &&) = delete; tflite(const tflite &) = delete; tflite & operator=(const tflite &) = delete; tflite(uint8_t *data, size_t size); bool run( std::vector<float> &t_out_buffer, std::vector<float> &t_cls_buffer, std::vector<float> &t_buffer, size_t region_size) noexcept; private: lib_tflite::ErrorReporter* error_reporter; lib_tflite::ops::builtin::BuiltinOpResolver resolver; std::unique_ptr<lib_tflite::FlatBufferModel> m_env; std::unique_ptr<lib_tflite::Interpreter> m_interpreter; std::vector<const char *> m_input_names; std::vector<const char *> m_output_names; size_t m_input_node_count; size_t m_output_node_count; std::vector<lib_tflite::Tensor> m_inputTensors; std::vector<lib_tflite::Tensor> m_outputTensors; std::vector<size_t> m_input_elem_size; std::vector<size_t> m_output_elem_size; std::vector<std::vector<int>> m_inputDims; std::vector<std::vector<int>> m_outputDims; std::vector<std::vector<float>> m_input_buffer; std::vector<std::vector<float>> m_output_buffer; std::unique_ptr<lib_tflite::MemoryAllocation> m_memory_info; }; #endif // TFLITE_DRIVER_HPP /* end_of_file */
错误日志
E/libc: Access denied finding property "ro.mediatek.platform" E/libc: Access denied finding property "ro.chipname" A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x13c6759bfc61 in tid 27936 (processing), pid 27893 (ample.nerveblox)
排查分析与解决建议
1. 线程安全问题
TFLite的Interpreter并非线程安全对象,即使构造函数在单线程执行,若run函数在另一个线程调用且无同步机制,会导致Interpreter内部状态被破坏,触发段错误。
- 解决方法:在类的private成员中添加
std::mutex m_interpreter_mutex,然后在run函数关键代码段添加锁:bool tflite::run(...) noexcept { std::lock_guard<std::mutex> lock(m_interpreter_mutex); // 原有输入拷贝、Invoke、输出拷贝代码 }
2. 预编译库与项目环境不匹配
测试项目和实际项目的ABI架构、NDK版本、编译参数可能存在差异,预编译库在测试环境兼容,但实际项目中因不匹配导致内存访问错误。
- 解决方法:
- 确认实际项目的ABI设置(如arm64-v8a/armeabi-v7a)与预编译库一致;
- 检查项目NDK版本是否与预编译库编译时的NDK版本匹配;
- 尝试用实际项目的编译环境重新编译TFLite库。
3. 输入数据拷贝越界
run函数中memcpy的第三个参数是元素数量,但memcpy按字节拷贝,未乘以sizeof(float)会导致拷贝长度不足;同时未校验t_buffer的实际大小,若小于m_input_elem_size[idx]会触发越界,破坏Interpreter内部结构。
- 解决方法:添加大小校验并修正拷贝长度:
for(size_t idx = 0; idx < this->m_input_node_count; idx++) { if (t_buffer.size() != this->m_input_elem_size[idx]) { log_error("Input buffer size mismatch\n"); return false; } float* data_ptr = m_interpreter->typed_input_tensor<float>(idx); memcpy(data_ptr, t_buffer.data(), this->m_input_elem_size[idx] * sizeof(float)); }
4. ErrorReporter未正确初始化
构造函数中error_reporter未初始化就传入BuildFromBuffer,可能导致TFLite内部错误报告时访问空指针,间接引发段错误。
- 解决方法:使用默认ErrorReporter:
auto error_reporter = lib_tflite::DefaultErrorReporter(); this->m_env = lib_tflite::FlatBufferModel::BuildFromBuffer((const char *)data, size, error_reporter);
5. Interpreter有效性检查
确认tflite对象未被意外销毁、m_interpreter指针未被非法修改,可在run函数开头添加检查:
if (!m_interpreter) { log_error("Interpreter is null\n"); return false; }
内容的提问来源于stack exchange,提问作者Turgut
相关产品推荐
相关产品推荐

