Repository: godot
Issue: Memory Leak With EditorNode3DGizmoPlugin and EditorInspectorPlugin When Rebuilding C# Project
Labels: bug,topic:editor,topic:dotnet,topic:3d

### Tested versions

-Reproducable in 4.3-dev6 and 4.2 stable

### System information

Windows 10

### Issue description

EditorNode3DGizmoPlugin seem to be unable to be unloaded when rebuilding the C# project, even if you dispose all related resources and set all references to null (in the EditorPlugin that created it).

For example:

```cs
internal sealed partial class TestGizmos : EditorNode3DGizmoPlugin
{
	public TestGizmos()
	{
		GD.Print("G CONS");
	}

	public override string _GetGizmoName()
	{
		return nameof(TestGizmos);
	}
	public override bool _HasGizmo(Node3D forNode3D)
	{
		return false;
	}

	protected override void Dispose(bool disposing)
	{
		GD.Print("G DIS");
	}
}
```

```cs
[Tool]
public sealed partial class TestPlugin : EditorPlugin
{
	private const int CHANGE_TO_REBUILD = 1;

	private readonly CSharpScript _testCS;
	private readonly Variant _test;
	private TestGizmos _testGizmos;

	// Called when plugin is enabled
	// Called after rebuild
	public TestPlugin()
	{
		GD.PrintS("P CONS");

		// The constructor and dispose are run on rebuilds which is dumb
		_testCS = GD.Load<CSharpScript>("res://addons/Test/TestGizmos.cs");
		_test = _testCS.New();
		_testGizmos = (TestGizmos)_test;

		AddNode3DGizmoPlugin(_testGizmos);
	}

	// Called when plugin is enabled
	//public override void _EnterTree()
	// Called when plugin is disabled
	//public override void _ExitTree()

	// Called when plugin is disabled
	// Called after rebuild
	protected override void Dispose(bool disposing)
	{
		GD.Print("P DIS");

		RemoveNode3DGizmoPlugin(_testGizmos);

		_testCS.Dispose();
		_test.Dispose();
		_testGizmos.Dispose();
		_testGizmos = null!;
	}
}
```

### Steps to reproduce

Run the above sample code, the MRP below is basically just that as an addon.
Change the constant int to force a rebuild of the project (otherwise it says it's already up-to-date).
This will dispose the plugin and the gizmos, but the gizmos remain loaded for the assembly reload.
Each time you do this, there will be an extra gizmos object available but not in use, and it also shows up in the editor View->Gizmos tab. You can see the constructor being called one extra time each rebuild you run.

You may ask "why not use EnterTree and ExitTree in the plugin?" and that's because those are not called for assembly reloads, which basically makes it impossible to effectively manage your resources (like docks) when rebuilding. Also it doesn't solve the problem since I originally had this code there instead of in the constructor and dispose and that's when I tried this. This works better but you still have a memory leak present. Even when disabling the plugin, all instances remain in the editor...

### Minimal reproduction project (MRP)

[mrp.zip](https://github.com/godotengine/godot/files/15183806/mrp.zip)

Essentially the behavior looks like this:
```
Plugin Constructor
Gizmos Constructor

(REBUILD)

Gizmos Dispose
Plugin Dispose
Gizmos Constructor <-- This is the old object that somehow persisted between rebuild
Plugin Constructor
Gizmos Constructor

(REBUILD)

Gizmos Dispose
Plugin Dispose
Gizmos Constructor <-- This is the 1st old object that somehow persisted between rebuild
Gizmos Constructor <-- This is the 2nd old object that somehow persisted between rebuild
Plugin Constructor
Gizmos Constructor
```