release object group

This commit is contained in:
Peng Lyu
2024-08-05 13:24:53 -07:00
parent af98c564c2
commit 30330d22a2
3 changed files with 32 additions and 10 deletions
+15 -3
View File
@@ -110,6 +110,14 @@ export class PlaywrightDriver {
return await this._cdpSession.send('Runtime.evaluate', options);
}
async releaseObjectGroup(parameters: Protocol.Runtime.releaseObjectGroupParameters): Promise<void> {
if (!this._cdpSession) {
throw new Error('CDP not started');
}
await this._cdpSession.send('Runtime.releaseObjectGroup', parameters);
}
async queryObjects(parameters: Protocol.Runtime.queryObjectsParameters): Promise<Protocol.Runtime.queryObjectsReturnValue> {
if (!this._cdpSession) {
throw new Error('CDP not started');
@@ -132,11 +140,15 @@ export class PlaywrightDriver {
}
let snapshot = '';
this._cdpSession.addListener('HeapProfiler.addHeapSnapshotChunk', ({ chunk }) => {
snapshot += chunk;
});
const listener = (c: { chunk: string }) => {
snapshot += c.chunk;
};
this._cdpSession.addListener('HeapProfiler.addHeapSnapshotChunk', listener);
await this._cdpSession.send('HeapProfiler.takeHeapSnapshot');
this._cdpSession.removeListener('HeapProfiler.addHeapSnapshotChunk', listener);
return snapshot;
}
+15 -5
View File
@@ -12,26 +12,28 @@ export class Profiler {
constructor(private readonly code: Code) {
}
async checkLeaks(classNames: string | string[], fn: () => Promise<void>): Promise<void> {
async checkObjectLeaks(classNames: string | string[], fn: () => Promise<void>): Promise<void> {
await this.code.driver.startCDP();
const countsBefore: { [key: string]: number } = {};
const instancesBefore = await getInstances(this.code.driver);
const classNamesArray = Array.isArray(classNames) ? classNames : [classNames];
for (const className of classNamesArray) {
const matchedInstances = instancesBefore.find(e => e.name !== undefined && e.name === className);
const matchedInstances = instancesBefore.value.find(e => e.name !== undefined && e.name === className);
if (!matchedInstances) {
throw new Error(`${className} not found`);
}
countsBefore[className] = matchedInstances.count;
}
await instancesBefore.dispose();
await fn();
const instancesAfter = await getInstances(this.code.driver);
const leaks: string[] = [];
for (const className of classNamesArray) {
const matchedInstancesAfter = instancesAfter.find(e => e.name !== undefined && e.name === className);
const matchedInstancesAfter = instancesAfter.value.find(e => e.name !== undefined && e.name === className);
if (!matchedInstancesAfter) {
throw new Error(`${className} not found`);
}
@@ -42,6 +44,8 @@ export class Profiler {
}
}
await instancesAfter.dispose();
if (leaks.length > 0) {
throw new Error(leaks.join('\n'));
}
@@ -126,7 +130,7 @@ function generateUuid() {
* This code is derived from https://github.com/SimonSiefke/vscode-memory-leak-finder
*--------------------------------------------------------------------------------------------*/
const getInstances = async (driver: PlaywrightDriver): Promise<Array<{ name: string; count: number }>> => {
const getInstances = async (driver: PlaywrightDriver): Promise<{ value: Array<{ name: string; count: number }>; dispose: () => Promise<void> }> => {
await driver.collectGarbage();
const objectGroup = `og:${generateUuid()}`;
const prototypeDescriptor = await driver.evaluate({
@@ -207,7 +211,13 @@ const getInstances = async (driver: PlaywrightDriver): Promise<Array<{ name: str
const fnResult2 = await getInstanceCountMap(driver, objectGroup, fnResult1.result);
const fnResult3 = await getInstanceCountArray(driver, objectGroup, fnResult2.result);
return fnResult3.result.value;
return {
value: fnResult3.result.value,
dispose: async () => {
// release object group
await driver.releaseObjectGroup({ objectGroup: objectGroup });
}
};
};
const getInstanceCountMap = async (driver: PlaywrightDriver, objectGroup: string, objects: Protocol.Runtime.RemoteObject) => {
@@ -25,7 +25,7 @@ export function setup(logger: Logger) {
cp.execSync('git reset --hard HEAD --quiet', { cwd: app.workspacePathOrFolder });
});
it('check heap leaks', async function () {
it.skip('check heap leaks', async function () {
const app = this.app as Application;
await app.profiler.checkHeapLeaks(['NotebookTextModel', 'NotebookCellTextModel', 'NotebookEventDispatcher'], async () => {
await app.workbench.notebook.openNotebook();
@@ -36,7 +36,7 @@ export function setup(logger: Logger) {
it('check object leaks', async function () {
const app = this.app as Application;
await app.profiler.checkLeaks(['NotebookTextModel'], async () => {
await app.profiler.checkObjectLeaks(['NotebookTextModel', 'NotebookCellTextModel', 'NotebookEventDispatcher'], async () => {
await app.workbench.notebook.openNotebook();
await app.workbench.quickaccess.runCommand('workbench.action.files.save');
await app.workbench.quickaccess.runCommand('workbench.action.closeActiveEditor');