Leaks detected through leak_tracker
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 初心者へのやさしさ
- 35/100
- issue の種類
- バグ
- 明瞭さ
- 説明が足りない
- 活発さ
- 静か
- 技術スタック
- dart
- 領域
- game-dev, performance
調査の方向性
まず package:leak_tracker を使って報告を再現し、position_component.dart、NotifyingVector2、Transform2D を調査します。特に _size リスナーと所有している ChangeNotifiers を確認してください。Flame チームと Component の破棄ライフサイクルを明確にし、報告された未破棄オブジェクトを排除するか、意図的に破棄対象ではないライフサイクル上のケースを文書化することを完了条件とします。
索引モデルが issue の本文から書いたものです。
説明
What happened?
I just tried enabling package:leak_tracker on my Flame game and it seems that Flame is leaking memory, or at the very least not properly disposing of objects.
From what I can tell, for example, Component is never disposed. (If I remember correctly from a discussion in a different forum, onRemove could be the end of the line, or it could be just before a component is re-parented. So that's not an equivalent of dispose().)
But PositionComponent creates _size, which is a NotifyingVector2, which is a ChangeNotifier. The dispose() method is never called on it.
Similarly, Transform2D has _offset (a NotifyingVector2) that is also never disposed. In fact, Transform2D doesn't even have dispose() implemented, despite being a ChangeNotifier and owning at least 3 other ChangeNotifiers.
Now, these are all reported as notDisposed (more on that here https://github.com/dart-lang/leak_tracker/blob/main/doc/leak_tracking/CONCEPTS.md and https://github.com/dart-lang/leak_tracker/blob/main/doc/leak_tracking/TROUBLESHOOT.md). If there's never anyone listening (even indirectly) to the undisposed objects, then Dart GC will do its job. At least that's how I understand it. But it would still be cleaner if there were no leaks, not even theoretical ones.
What do you expect?
No leaks.
How can we reproduce this?
The best method for me has been this. Let's say you have a sample or demo or a bigger game.
dependencies:
leak_tracker: ^11.0.2
Then in main.dart:
if (!kReleaseMode && kLeakTrackingEnabled) {
log.fine('Setting up pkg:leak_tracker');
setupLeakTracking();
}
Then in something like lib/utils/leak_tracking.dart:
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:leak_tracker/leak_tracker.dart';
import 'package:logging/logging.dart';
const bool kLeakTrackingEnabled = bool.fromEnvironment(
'track-leaks',
defaultValue: true,
);
const bool kLeakTrackingStackTraces = bool.fromEnvironment(
'track-leaks-stack-traces',
defaultValue: true,
);
/// Sets up leak tracking via `pkg:leak_tracker`.
void setupLeakTracking() {
final log = Logger('setupLeakTracking');
FlutterMemoryAllocations.instance.addListener(
(ObjectEvent event) => LeakTracking.dispatchObjectEvent(event.toMap()),
);
LeakTracking.phase = PhaseSettings(
leakDiagnosticConfig: LeakDiagnosticConfig(
collectStackTraceOnStart: kLeakTrackingStackTraces,
),
);
LeakTracking.start(config: LeakTrackingConfig(stdoutLeaks: false));
Timer.periodic(const Duration(seconds: 1), (_) async {
final leaks = await LeakTracking.collectLeaks();
if (leaks.total > 0) {
log.warning(
'${leaks.total} memory leaks detected by pkg:leak_tracker:\n'
'${leaks.toYaml(phasesAreTests: false)}',
);
if (!kLeakTrackingStackTraces) {
log.info(
'To learn where these objects were created, '
're-run the app with `--track-leaks-stack-traces true`.',
);
}
}
});
}
Then just run the sample and start going through it. Assuming you have logging set up properly, you'll be seeing things like:
40 memory leaks detected by pkg:leak_tracker:
# The text is generated by leak_tracker.
# For leak troubleshooting tips open:
# https://github.com/dart-lang/leak_tracker/blob/main/doc/leak_tracking/TROUBLESHOOT.md
notDisposed:
total: 40
objects:
NotifyingVector2:
identityHashCode: 424350735
context:
start: >
#6______setupLeakTracking.<anonymous_closure>_(package:giant_robot/util/leak_tracking.dart:22:41)
#7______FlutterMemoryAllocations.dispatchObjectEvent_(package:flutter/src/foundation/memory_allocations.dart:243:23)
#8______FlutterMemoryAllocations.dispatchObjectCreated_(package:flutter/src/foundation/memory_allocations.dart:281:5)
#9______debugMaybeDispatchCreated_(package:flutter/src/foundation/debug.dart:152:39)
#10_____ChangeNotifier.maybeDispatchObjectCreation.<anonymous_closure>_(package:flutter/src/foundation/change_notifier.dart:238:9)
#11_____ChangeNotifier.maybeDispatchObjectCreation_(package:flutter/src/foundation/change_notifier.dart:242:6)
#12_____ChangeNotifier.addListener_(package:flutter/src/foundation/change_notifier.dart:276:7)
#13_____new_PositionComponent_(package:flame/src/components/position_component.dart:96:11)
#14_____new__Entity&PositionComponent&HasGameReference_(package:giant_robot/game/entity/entity.dart)
#15_____new__Entity&PositionComponent&HasGameReference&CollisionCallbacks_(package:giant_robot/game/entity/entity.dart)
#16_____new__Entity&PositionComponent&HasGameReference&CollisionCallbacks&UpdateSeldom_(package:giant_robot/game/entity/entity.dart)
#17_____new_Entity_(package:giant_robot/game/entity/entity.dart:369:39)
#18_____WeaponPart._getFallbackProjectile_(package:giant_robot/game/combat/weapon_part.dart:677:12)
#19_____new_WeaponPart_(package:giant_robot/game/combat/weapon_part.dart:137:33)
#20_____createGblin_(package:giant_robot/game/entity/prototypes/gblin.dart:55:7)
#21______loadBadGuysFrom_(package:giant_robot/game/levels/level_definition_loader.dart:321:35)
...
The way you use the stacktrace is this:
- Find the first fame that isn't in
setupLeakTrackingnor in a Flutter internal file. In the first case above, that's frame#13, which isnew PositionComponent. - This tells you where the leaked object was created (but never disposed).
In this particular case, position_component.dart:96:11 is this line:
_size.addListener(_onModifiedSizeOrAnchor);
As explained in the TROUBLESHOOTING guide (linked above), ChangeNotifiers are registered only when someone first listens to them. There's a way to fix this and let a custom ChangeNotifier be registered at creation time. Here. I think it would be good to have that set up for NotifyingVector2 and Transform2D, at the very least.
What steps should take to fix this?
No response
Do have an example of where the bug occurs?
No response
Relevant log output
Execute in a terminal and put output into the code block below
Output of: flutter doctor -v
[✓] Flutter (Channel stable, 3.44.8, on macOS 15.7.7 24G720 darwin-arm64, locale en-US) [449ms]
• Flutter version 3.44.8 on channel stable at /Users/filiph/fvm/versions/stable
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 058e0af2c2 (9 days ago), 2026-07-23 10:56:21 -0700
• Engine revision 0cd610717b
• Dart version 3.12.2
• DevTools version 2.57.0
• Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop,
enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets,
enable-swift-package-manager, omit-legacy-version-file, enable-lldb-debugging,
enable-uiscene-migration
[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0) [1,644ms]
• Android SDK at /Users/filiph/Library/Android/sdk
• Emulator version 36.4.9.0 (build_id 14788078) (CL:N/A)
• Platform android-36, build-tools 36.0.0
• Java binary at: /usr/bin/java
This JDK was found in the system PATH.
To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
• Java version OpenJDK Runtime Environment (build 19+36-2238)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 26.3) [947ms]
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 17C529
• CocoaPods version 1.16.2
[✓] Chrome - develop for the web [4ms]
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Connected device (2 available) [6.4s]
• macOS (desktop) • macos • darwin-arm64 • macOS 15.7.7 24G720 darwin-arm64
• Chrome (web) • chrome • web-javascript • Google Chrome 150.0.7871.187
! Error: Browsing on the local area network for Filip Hracek’s iPad. Ensure the device is
unlocked and attached with a cable or associated with the same local area network as this
Mac.
The device must be opted into Developer Mode to connect wirelessly. (code -27)
! Error: Browsing on the local area network for Raindead S M4 iPad. Ensure the device is
unlocked and attached with a cable or associated with the same local area network as this
Mac.
The device must be opted into Developer Mode to connect wirelessly. (code -27)
[✓] Network resources [539ms]
• All expected network resources are available.
• No issues found!
Affected platforms
All
Other information
I may be able to work on this but first, the Flame team needs to figure out whether Components should be disposed at some point, for example. If not, than much of this problem is unsolvable, as far as I can tell.
Are you interested in working on a PR for this?
- I want to work on this
- 主要言語
- Dart
- スター
- 10.8k
- フォーク
- 1.1k
- 平均マージ
- 1日 15時間
- マージ済み PR(30日)
- 50
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
flame-engine/flame のほかの issue
-
flame_tiled: tileset image in a subfolder of an external .tsx resolves to the wrong path対応中かも @ufrshubham が 1 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 35/100
flame-engine/flame#4117 · コメント 1 件 · リアクション 1 件 ·
メンテナーはふだん 1 日以内に返信
-
enhancement v2
難易度 4/5 3〜5日 初心者へのやさしさ 25/100
flame-engine/flame#4116 ·
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
flame-engine/flame#4063 ·
メンテナーはふだん 1 日以内に返信
-
TextComponent shadows are not affected by OpacityEffect対応中かも @spydon が 39 日前に担当しました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 72/100
flame-engine/flame#4013 ·
メンテナーはふだん 1 日以内に返信
-
enhancement
難易度 5/5 1週間以上 初心者へのやさしさ 35/100
flame-engine/flame#4012 · コメント 4 件 ·
メンテナーはふだん 1 日以内に返信
flame-engine/flame の issue をすべて見る
似ている issue
-
package:code_builder type-bug
難易度 2/5 1〜3時間 初心者へのやさしさ 90/100
メンテナーはふだん 1 日以内に返信
-
type:feature
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
メンテナーはふだん 1 日以内に返信
-
photos
難易度 1/5 1時間未満 初心者へのやさしさ 91/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
venera-app/venera-prime#45 ·
-
area: ui feature priority: medium
難易度 1/5 1時間未満 初心者へのやさしさ 90/100
メンテナーはふだん 1 日以内に返信