-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ensure all references are released when Terminal.dispose is called #1525
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM in general, but I would suggest someone else reviewing it as well, since it deals with a crucial part of the project.
this._disposables.push(this._terminal.addDisposableListener('resize', data => this._onResize(data.cols, data.rows))); | ||
this._disposables.push(this._terminal.addDisposableListener('refresh', data => this._refreshRows(data.start, data.end))); | ||
this._disposables.push(this._terminal.addDisposableListener('scroll', data => this._refreshRows())); | ||
this.register(this._renderRowsDebouncer); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just an idea; would it make sense to replace this.register(...
with TypeScript decorators? This way we could keep disposable properties declared outside the constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean something like this? (if it works)
function register(target: any, key: string) {
let _val = this[key];
const getter = () => _val;
const setter = (newVal) => {
if (_val) {
_val.dispose();
}
target.register(newVal);
_val = newVal;
};
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked into this and I don't think we can do it. For starters decorators are experimental, I switched it on and tried to get it working but it seemed to be acting not as I expected. Maybe we can do this in the future?
demo/main.js
Outdated
|
||
term.on('paste', function (data, ev) { | ||
term._core,register(term.addDisposableListener('paste', function (data, ev) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
term._core,register
looks like a typo to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
* Registers a disposable object. | ||
* @param d The disposable to register. | ||
*/ | ||
public register<T extends IDisposable>(d: T): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think registerDisposable
or addDisposable
would be better, especially because classes that inherit from Disposable might want to use register
with a totally different meaning. Say we have an AddonRegistry
class that extends Disposable
, it would certainly get very confusing what AddonRegistry.register
would do 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about register
taking a list of arguments ...disposables
, so we could simply register multiple disposables at once, e.g.:
this._terminal.core.register(
this._terminal.addDisposableListener('blur', () => this._clearLiveRegion()),
this._terminal.addDisposableListener('linefeed', () => this._lineFeed()),
this._terminal.addDisposableListener('focus', () => this._focus())
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think registerDisposable or addDisposable would be better, especially because classes that inherit from Disposable might want to use register with a totally different meaning.
I was trying to make it not so verbose as the lines can already get quite long. This also matches the naming scheme we use in vscode https://github.com/Microsoft/vscode/blob/26af5f5392012067294755ef91cf66fc782b4d48/src/vs/base/common/lifecycle.ts#L70
What do you think about register taking a list of arguments ...disposables, so we could simply register multiple disposables at once, e.g.:
You can already do this with:
this._terminal.core._disposables.push(a, b, c);
I prefer the look of the other way personally
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine with me, your call 👍
@Tyriar Should I give this a final test / review? |
@mofux I think this is ready for final review, CI failure was unrelated. |
Works like a charm, ready to merge from my side 👍 |
🎉 |
This PR adds the following:
Disposable
that is extended by a number of classes and provides aregister
function to register disposables and adispose
function which disposes themutil/Dom.ts
toui/Lifecycle.ts
After these changes, when a heap snapshot is taken it will no longer show
Terminal
in the heap. The following was taken after filling the buffer and disposing the terminal:This is what it looked like before (with demo and internal Terminal references holding onto the
Terminal
):Fixes #1518