如何解决Flutter中TFLite的‘Interpreter busy’平台异常问题?
问题描述
我正在开发一款Android Flutter应用,使用TFLite的YOLOv5模型实现单类别实时检测。应用安装到设备后,运行2-3秒就会崩溃,抛出如下异常:
错误信息
E/flutter (16282): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(Failed to run model, Interpreter busy, java.lang.RuntimeException: Interpreter busy E/flutter (16282): at sq.flutter.tflite.TflitePlugin$TfliteTask.<init>(TflitePlugin.java:450) E/flutter (16282): at sq.flutter.tflite.TflitePlugin$RunModelOnFrame.<init>(TflitePlugin.java:545) E/flutter (16282): at sq.flutter.tflite.TflitePlugin.onMethodCall(TflitePlugin.java:117) E/flutter (16282): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:258) E/flutter (16282): at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:295) E/flutter (16282): at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:322) E/flutter (16282): at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12) E/flutter (16282): at android.os.Handler.handleCallback(Handler.java:938) E/flutter (16282): at android.os.Handler.dispatchMessage(Handler.java:99) E/flutter (16282): at android.os.Looper.loop(Looper.java:236) E/flutter (16282): at android.app.ActivityThread.main(ActivityThread.java:7876) E/flutter (16282): at java.lang.reflect.Method.invoke(Native Method) E/flutter (16282): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:656) E/flutter (16282): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:967) E/flutter (16282): , null) E/flutter (16282): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:668:7) E/flutter (16282): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:315:18) E/flutter (16282): <asynchronous suspension> E/flutter (16282): #2 Tflite.runModelOnFrame (package:tflite/tflite.dart:73:12) E/flutter (16282): <asynchronous suspension> E/flutter (16282): #3 _HomeState.runModel (package:bat_app/Home.dart:43:25) E/flutter (16282): <asynchronous suspension> E/flutter (16282): D/OOMEventManagerFK(16282): checkEventAndDumpForJE: 0 I/Process (16282): Sending signal. PID: 16282 SIG: 9 Lost connection to device.
我已经查看过StackOverflow上的相关解决方案,但都无效,为此问题耗费了5小时,求永久解决方案。
项目依赖(pubspec.yaml)
My dependencies are (pubspec.yaml):
name: bat_app description: A new Flutter project. publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: sdk: '>=2.16.1 <3.0.0' dependencies: flutter: sdk: flutter tflite: ^1.1.2 camera: ^0.10.3+2 cupertino_icons: ^1.0.2 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^1.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter packages. flutter: uses-material-design: true assets: - assets/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware # For details regarding adding assets from package dependencies, see # https://flutter.dev/assets-and-images/#from-packages # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro # fonts: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages
home.dart页面代码
My home.dart page code:
import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; import 'package:tflite/tflite.dart'; import 'main.dart'; class Home extends StatefulWidget { const Home({Key? key}) : super(key: key); @override State<Home> createState() => _HomeState(); } class _HomeState extends State<Home> { CameraImage? cameraImage; CameraController? cameraController; String output = ''; @override void initState() { super.initState(); loadModel(); loadCamera(); } loadCamera() { cameraController = CameraController(cameras![0], ResolutionPreset.medium); cameraController!.initialize().then((value) { if (!mounted) { return; } else { setState(() { cameraController!.startImageStream((imageStream) { cameraImage = imageStream; runModel(); }); }); } }); } runModel() async { if (cameraImage != null) { var predictions = await Tflite.runModelOnFrame( bytesList: cameraImage!.planes.map((plane) { return plane.bytes; }).toList(), imageHeight: cameraImage!.height, imageWidth: cameraImage!.width, imageMean: 127.5, imageStd: 127.5, rotation: 90, numResults: 2, threshold: 0.6, asynch: true); predictions!.forEach((element) { setState(() { output = element['label']; }); }); } } loadModel() async { await Tflite.loadModel( model: "assets/model.tflite", labels: "assets/labels.txt"); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Racket Bat Scoring'), ), body: Column( children: [ Padding( padding: const EdgeInsets.all(20), child: Container( height: MediaQuery.of(context).size.height * 0.7, width: MediaQuery.of(context).size.width, child: !cameraController!.value.isInitialized ? Container() : AspectRatio( aspectRatio: cameraController!.value.aspectRatio, child: CameraPreview(cameraController!), ), ), ), Text(output, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20)) ], ), ); } }
解决方案
核心问题
相机startImageStream会以约30fps的频率回调,每一次回调都触发runModel,但你使用的tflite插件的解释器是单实例单线程的,前一次模型推理还未完成,新的请求就已到达,直接导致Interpreter busy异常,最终因任务堆积引发崩溃。
具体修复步骤
1. 添加推理任务锁,避免并发调用
在_HomeState中添加布尔变量标记当前是否正在执行推理,确保同一时间只有一个推理任务运行:
class _HomeState extends State<Home> { CameraImage? cameraImage; CameraController? cameraController; String output = ''; // 新增锁变量 bool _isRunningInference = false; // ... 其他代码保持不变
2. 修改runModel方法,加入锁判断
更新runModel,仅当无推理任务时才执行模型调用:
runModel() async { // 若正在推理或无相机帧,直接返回 if (cameraImage == null || _isRunningInference) { return; } _isRunningInference = true; try { var predictions = await Tflite.runModelOnFrame( bytesList: cameraImage!.planes.map((plane) { return plane.bytes; }).toList(), imageHeight: cameraImage!.height, imageWidth: cameraImage!.width, imageMean: 127.5, imageStd: 127.5, rotation: 90, numResults: 2, threshold: 0.6, asynch: true); if (predictions != null && predictions.isNotEmpty) { setState(() { output = predictions.first['label']; }); } } finally { // 无论成功失败,都释放锁 _isRunningInference = false; } }
3. 优化相机帧处理(可选但推荐)
若无需30fps的实时推理,可降低帧处理频率,比如每2帧处理一次,减少推理压力:
class _HomeState extends State<Home> { // ... 其他变量 int _frameCount = 0; // 修改loadCamera中的帧回调逻辑 cameraController!.startImageStream((imageStream) { cameraImage = imageStream; _frameCount++; // 每2帧处理一次推理 if (_frameCount % 2 == 0) { runModel(); } });
4. 替换老旧tflite插件(推荐永久解决)
你当前使用的tflite: ^1.1.2是长期未维护的版本,官方推荐使用google_mlkit_object_detection或tflite_flutter插件,后者是官方维护的TFLite Flutter绑定,稳定性和性能更优:
- 更新pubspec.yaml中的依赖:
dependencies: # 移除旧的tflite依赖 # tflite: ^1.1.2 tflite_flutter: ^0.10.1 tflite_flutter_helper: ^0.4.0 camera: ^0.10.3+2
- 该插件支持多线程推理,能从根源上避免
Interpreter busy问题。
5. 释放资源(避免内存泄漏)
在页面销毁时释放相机和TFLite资源:
@override void dispose() { cameraController?.stopImageStream(); cameraController?.dispose(); Tflite.close(); super.dispose(); }
验证修复
完成上述修改后重新运行应用,相机帧会被有序处理,不会再出现Interpreter busy异常,应用可稳定运行。
内容的提问来源于stack exchange,提问作者Md Mahadi Hasan Sany
相关产品推荐
相关产品推荐

