Steps to reproduce:
- Create or open any project
- Add the attached script “BugReproScript.cs” inside an Assets folder
- Reimport any script or asset (right-click the “BugReproScript” and select reimport)
- Observe the editor layout tabs
Actual result: Empty layout tabs appear in the editor and cannot be closed or docked
Expected result: The window close cleanly without leaving behind orphaned or corrupted tabs in the layout
Reproducible with: 6000.3.0a1 (4592b02ab560), 6000.3.18f1, 6000.5.1f1, 6000.6.0b1, 6000.7.0a1
Not reproducible with: 6000.2.0b2 (d4c40f50eb81), 6000.0.78f1
Reproducible on: Windows 11
Not reproducible on: No other environments tested
Note: This layout serialization corruption leaks the EditorWindow instances in memory, causing a cumulative memory leak over subsequent domain reloads
UPDATE
This issue occurs because EditorWindows are (unintentionally) being opened within the AssetImporterWorker process instead of the "main" Unity process.
Unlike other secondary processes and workers, the AssetImporter is a "full GUI" Editor instance and has all the same Editor behaviors, including Domain Reloads and their subsequent callbacks. That is, the InitializeOnLoadMethod handler is also called within this process in addition to the main Editor.
However, AssetImporter isn't design for windowing and so the (native) windowing objects become "stuck" and won't close. If you manually kill the AssetImporter process within TaskManger this will force close all these orphan windows.
The fix is simply to prevent creating native windowing objects from AssetImporter
As an aside, nothing is being "leaked" despite the comment above. The orphaned EditorWindows are all in the AssetImporter process and aren't within the main Editor process. But since AssetImporter is a child (forked) process, Windows groups them all together in the Taskbar.
NOTE: LinuxEditor has similar issues in this scenario but MacEditor does not.
WORKAROUND
Add the following check within the start of InitialzeOnLoadMethod handler, i.e. before opening any windows:
if (AssetDatabase.IsAssetImportWorkerProcess())
return;
Essentially, the actual fix will do the same thing (just in the native code).