Skip to content

Commit c3a2ed9

Browse files
committed
Improve memory management logic
1 parent 61a4bbb commit c3a2ed9

File tree

9 files changed

+91
-71
lines changed

9 files changed

+91
-71
lines changed

libs/component/runtime/resources/stubs/saucer.stub.php

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,39 @@
1515
final class CSaucerWebViewEventsStruct extends CData
1616
{
1717
/**
18-
* @var \Closure(CData, CData):void
18+
* @var null|\Closure(CData, CData):void
1919
*/
20-
public \Closure $onDomReady;
20+
public null|\Closure $onDomReady;
2121

2222
/**
23-
* @var \Closure(CData, string, CData):void
23+
* @var null|\Closure(CData, string, CData):void
2424
*/
25-
public \Closure $onNavigated;
25+
public null|\Closure $onNavigated;
2626

2727
/**
28-
* @var \Closure(CData, CData, CData):void
28+
* @var null|\Closure(CData, CData, CData):void
2929
*/
30-
public \Closure $onNavigating;
30+
public null|\Closure $onNavigating;
3131

3232
/**
33-
* @var \Closure(CData, CData, CData):void
33+
* @var null|\Closure(CData, CData, CData):void
3434
*/
35-
public \Closure $onFaviconChanged;
35+
public null|\Closure $onFaviconChanged;
3636

3737
/**
38-
* @var \Closure(CData, string, CData):void
38+
* @var null|\Closure(CData, string, CData):void
3939
*/
40-
public \Closure $onTitleChanged;
40+
public null|\Closure $onTitleChanged;
4141

4242
/**
43-
* @var \Closure(CData, State::SAUCER_STATE_*, CData):void
43+
* @var null|\Closure(CData, State::SAUCER_STATE_*, CData):void
4444
*/
45-
public \Closure $onLoad;
45+
public null|\Closure $onLoad;
4646

4747
/**
48-
* @var \Closure(CData, string, int<0, max>, CData):void
48+
* @var null|\Closure(CData, string, int<0, max>, CData):void
4949
*/
50-
public \Closure $onMessage;
50+
public null|\Closure $onMessage;
5151
}
5252

5353
}
@@ -68,39 +68,39 @@ final class CSaucerWebViewEventsStruct extends CData
6868
final class CSaucerWindowEventsStruct extends CData
6969
{
7070
/**
71-
* @var \Closure(CData, bool): void
71+
* @var null|\Closure(CData, bool): void
7272
*/
73-
public \Closure $onDecorated;
73+
public null|\Closure $onDecorated;
7474

7575
/**
76-
* @var \Closure(CData, bool): void
76+
* @var null|\Closure(CData, bool): void
7777
*/
78-
public \Closure $onMaximize;
78+
public null|\Closure $onMaximize;
7979

8080
/**
81-
* @var \Closure(CData, bool): void
81+
* @var null|\Closure(CData, bool): void
8282
*/
83-
public \Closure $onMinimize;
83+
public null|\Closure $onMinimize;
8484

8585
/**
86-
* @var \Closure(CData): Policy::SAUCER_POLICY_*
86+
* @var null|\Closure(CData): Policy::SAUCER_POLICY_*
8787
*/
88-
public \Closure $onClosing;
88+
public null|\Closure $onClosing;
8989

9090
/**
91-
* @var \Closure(CData): void
91+
* @var null|\Closure(CData): void
9292
*/
93-
public \Closure $onClosed;
93+
public null|\Closure $onClosed;
9494

9595
/**
96-
* @var \Closure(CData, int<0, 2147483647>, int<0, 2147483647>): void
96+
* @var null|\Closure(CData, int<0, 2147483647>, int<0, 2147483647>): void
9797
*/
98-
public \Closure $onResize;
98+
public null|\Closure $onResize;
9999

100100
/**
101-
* @var \Closure(CData, bool): void
101+
* @var null|\Closure(CData, bool): void
102102
*/
103-
public \Closure $onFocus;
103+
public null|\Closure $onFocus;
104104
}
105105

106106
}

libs/component/runtime/src/Extension/Registry.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
use Boson\Extension\Exception\ExtensionLoadingException;
1111
use Boson\Extension\Exception\ExtensionNotFoundException;
1212
use Boson\Extension\Loader\DependencyGraph;
13-
use Internal\Destroy\Destroyable;
13+
use Internal\Destroy\Destroyable as DestroyableInterface;
1414
use Psr\Container\ContainerInterface;
1515

1616
/**
1717
* @template TContext of IdentifiableInterface
1818
*/
19-
final class Registry implements ContainerInterface, Destroyable
19+
final class Registry implements ContainerInterface, DestroyableInterface
2020
{
2121
/**
2222
* @var list<object>
@@ -121,13 +121,13 @@ public function destroy(): void
121121
$destroyed = new \SplObjectStorage();
122122

123123
foreach ($this->privateExtensions as $extension) {
124-
if ($extension instanceof Destroyable) {
124+
if ($extension instanceof DestroyableInterface) {
125125
$destroyed->offsetSet($extension);
126126
}
127127
}
128128

129129
foreach ($this->publicExtensions as $extension) {
130-
if ($extension instanceof Destroyable) {
130+
if ($extension instanceof DestroyableInterface) {
131131
$destroyed->offsetSet($extension);
132132
}
133133
}

libs/component/runtime/src/WebView/Manager/WebViewHandlerFactory.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
namespace Boson\WebView\Manager;
66

7-
use Boson\Application;
87
use Boson\Component\Saucer\SaucerInterface;
8+
use Boson\Component\WeakType\ObservableSetInterface;
9+
use Boson\Component\WeakType\ObservableWeakSet;
910
use Boson\Shared\Marker\RequiresDealloc;
1011
use Boson\WebView\Exception\WebViewException;
1112
use Boson\WebView\WebViewCreateInfo;
@@ -21,16 +22,27 @@
2122
*/
2223
final readonly class WebViewHandlerFactory
2324
{
25+
/**
26+
* @var ObservableSetInterface<WebViewId>
27+
*/
28+
private ObservableSetInterface $ids;
29+
2430
public function __construct(
2531
private SaucerInterface $saucer,
26-
) {}
32+
) {
33+
$this->ids = new ObservableWeakSet();
34+
}
2735

2836
public function create(Window $window, WebViewCreateInfo $info): WebViewId
2937
{
30-
return WebViewId::fromHandle(
38+
$id = WebViewId::fromHandle(
3139
api: $this->saucer,
3240
handle: $this->createWebViewHandle($window, $info),
3341
);
42+
43+
return $this->ids->watch($id, function (WebViewId $id) {
44+
// $this->saucer->saucer_webview_free($id->ptr);
45+
});
3446
}
3547

3648
#[RequiresDealloc]

libs/component/runtime/src/WebView/Manager/WebViewManager.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Boson\Dispatcher\DelegateEventListener;
1111
use Boson\Dispatcher\EventListener;
1212
use Boson\Dispatcher\EventListenerProvider;
13+
use Boson\Extension\Registry;
1314
use Boson\WebView\Exception\WindowDereferenceException;
1415
use Boson\WebView\WebView;
1516
use Boson\WebView\WebViewCreateInfo;
@@ -120,7 +121,7 @@ private function createEventListener(PsrEventDispatcherInterface $dispatcher): E
120121
*/
121122
private function createWebViewHandlerFactory(): WebViewHandlerFactory
122123
{
123-
return new WebViewHandlerFactory($this->api, $this->window);
124+
return new WebViewHandlerFactory($this->api);
124125
}
125126

126127
public function create(WebViewCreateInfo $info = new WebViewCreateInfo()): WebView

libs/component/runtime/src/WebView/WebView.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
use Boson\WebView\Exception\WindowDereferenceException;
3030
use Boson\Window\Window;
3131
use Boson\Window\WindowId;
32-
use Internal\Destroy\Destroyable;
32+
use Internal\Destroy\Destroyable as DestroyableInterface;
3333
use JetBrains\PhpStorm\Language;
3434
use Psr\Container\ContainerInterface;
3535
use Psr\EventDispatcher\EventDispatcherInterface;
@@ -42,7 +42,7 @@ final class WebView implements
4242
IdentifiableInterface,
4343
EventListenerInterface,
4444
ContainerInterface,
45-
Destroyable
45+
DestroyableInterface
4646
{
4747
use EventListenerProvider;
4848

libs/component/runtime/src/Window/Api/LifecycleEvents/LifecycleEventsListener.php

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@
1919
use Boson\Window\Event\WindowResized;
2020
use Boson\Window\Window;
2121
use FFI\CData;
22-
use Internal\Destroy\Destroyable;
22+
use Internal\Destroy\Destroyable as DestroyableInterface;
2323

24-
final class LifecycleEventsListener extends LoadedWindowExtension implements Destroyable
24+
final class LifecycleEventsListener extends LoadedWindowExtension implements
25+
DestroyableInterface
2526
{
2627
/**
2728
* @var non-empty-string
@@ -61,7 +62,7 @@ final class LifecycleEventsListener extends LoadedWindowExtension implements Des
6162
/**
6263
* @var array<WindowEvent::SAUCER_WINDOW_EVENT_*, int<0, max>>
6364
*/
64-
private readonly array $listeners;
65+
private array $listeners;
6566

6667
public function __construct(
6768
Window $window,
@@ -273,5 +274,17 @@ public function destroy(): void
273274
foreach ($this->listeners as $event => $id) {
274275
$this->saucer->saucer_window_off($this->ptr, $event, $id);
275276
}
277+
278+
$this->handlers->onDecorated = null;
279+
$this->handlers->onMaximize = null;
280+
$this->handlers->onMinimize = null;
281+
$this->handlers->onClosing = null;
282+
$this->handlers->onClosed = null;
283+
$this->handlers->onResize = null;
284+
$this->handlers->onFocus = null;
285+
286+
\FFI::free(\FFI::addr($this->handlers));
287+
288+
$this->listeners = [];
276289
}
277290
}

libs/component/runtime/src/Window/Manager/WindowHandlerFactory.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
use Boson\Application;
88
use Boson\Component\Saucer\SaucerInterface;
9+
use Boson\Component\WeakType\ObservableSetInterface;
10+
use Boson\Component\WeakType\ObservableWeakSet;
911
use Boson\Shared\Marker\RequiresDealloc;
1012
use Boson\Window\Exception\WindowException;
1113
use Boson\Window\WindowCreateInfo;
@@ -18,17 +20,28 @@
1820
*/
1921
final readonly class WindowHandlerFactory
2022
{
23+
/**
24+
* @var ObservableSetInterface<WindowId>
25+
*/
26+
private ObservableSetInterface $ids;
27+
2128
public function __construct(
2229
private SaucerInterface $saucer,
2330
private Application $app,
24-
) {}
31+
) {
32+
$this->ids = new ObservableWeakSet();
33+
}
2534

2635
public function create(WindowCreateInfo $info): WindowId
2736
{
28-
return WindowId::fromHandle(
37+
$id = WindowId::fromHandle(
2938
api: $this->saucer,
3039
handle: $this->createWindowHandle($info),
3140
);
41+
42+
return $this->ids->watch($id, function (WindowId $id): void {
43+
$this->saucer->saucer_window_free($id->ptr);
44+
});
3245
}
3346

3447
#[RequiresDealloc]

libs/component/runtime/src/Window/Manager/WindowManager.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
use Boson\Window\Event\WindowDestroyed;
1717
use Boson\Window\Window;
1818
use Boson\Window\WindowCreateInfo;
19-
use Internal\Destroy\Destroyable;
19+
use Internal\Destroy\Destroyable as DestroyableInterface;
2020
use Psr\EventDispatcher\EventDispatcherInterface;
2121
use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface;
2222

@@ -34,7 +34,7 @@ final class WindowManager implements
3434
WindowCollectionInterface,
3535
WindowFactoryInterface,
3636
\IteratorAggregate,
37-
Destroyable
37+
DestroyableInterface
3838
{
3939
use EventListenerProvider;
4040

@@ -207,8 +207,6 @@ public function destroy(): void
207207
/** @var Window $window */
208208
foreach ($this->windows as $window) {
209209
$this->windows->detach($window);
210-
211-
$window->destroy();
212210
}
213211

214212
$this->default = null;

libs/component/runtime/src/Window/Window.php

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
use Boson\Window\Internal\Size\ManagedWindowMinBounds;
2727
use Boson\Window\Internal\Size\ManagedWindowSize;
2828
use Boson\Window\Manager\WindowFactoryInterface;
29-
use Internal\Destroy\Destroyable;
3029
use Psr\Container\ContainerInterface;
3130
use Psr\EventDispatcher\EventDispatcherInterface;
3231

@@ -37,8 +36,7 @@
3736
final class Window implements
3837
IdentifiableInterface,
3938
EventListenerInterface,
40-
ContainerInterface,
41-
Destroyable
39+
ContainerInterface
4240
{
4341
use EventListenerProvider;
4442

@@ -651,7 +649,12 @@ private function registerDefaultEventListeners(): void
651649
$this->listener->addEventListener(WindowClosed::class, function (): void {
652650
$this->isClosed = true;
653651

654-
$this->destroy();
652+
$this->extensions->destroy();
653+
$this->webviews->destroy();
654+
655+
$this->listener->removeAllEventListeners();
656+
657+
\gc_collect_cycles();
655658
});
656659

657660
$this->listener->addEventListener(WindowMinimized::class, function (WindowMinimized $e): void {
@@ -879,26 +882,6 @@ public function close(): void
879882
$this->saucer->saucer_window_close($this->id->ptr);
880883
}
881884

882-
/**
883-
* @internal for internal usage only
884-
*/
885-
public function destroy(): void
886-
{
887-
$this->extensions->destroy();
888-
$this->webviews->destroy();
889-
890-
$this->listener->removeAllEventListeners();
891-
892-
\gc_collect_cycles();
893-
}
894-
895-
public function __destruct()
896-
{
897-
$this->destroy();
898-
899-
$this->saucer->saucer_window_free($this->id->ptr);
900-
}
901-
902885
public function __get(string $name): object
903886
{
904887
return $this->extensions->get($name);

0 commit comments

Comments
 (0)