mirror of
https://github.com/dream-num/univer.git
synced 2026-09-01 15:29:43 +08:00
fix: fix last memory leak and make memory CI more strict (#4229)
This commit is contained in:
Vendored
+1
@@ -15,6 +15,7 @@ declare global {
|
||||
// eslint-disable-next-line ts/naming-convention
|
||||
interface Window {
|
||||
E2EControllerAPI: IE2EControllerAPI;
|
||||
univer: any;
|
||||
// eslint-disable-next-line ts/no-explicit-any
|
||||
univerAPI: any;
|
||||
}
|
||||
|
||||
+25
-34
@@ -16,53 +16,44 @@
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { getMetrics } from './util';
|
||||
|
||||
const MAX_MEMORY_OVERFLOW = 5_000_000; // 5MB
|
||||
const MAX_UNIT_MEMORY_OVERFLOW = 1_000_000; // 1MB
|
||||
|
||||
// There are some compiled code and global cache, so we make some room
|
||||
// for this. But we need to make sure that a Univer object cannot fit
|
||||
// in this size.
|
||||
const MAX_UNIVER_MEMORY_OVERFLOW = 5_000_000;
|
||||
|
||||
test('memory', async ({ page }) => {
|
||||
test.setTimeout(60_000);
|
||||
|
||||
await page.goto('http://localhost:3000/sheets/');
|
||||
await page.waitForTimeout(2000);
|
||||
await page.waitForTimeout(5000);
|
||||
|
||||
const memoryBeforeLoad = (await getMetrics(page)).JSHeapUsedSize;
|
||||
console.log('Memory before load:', memoryBeforeLoad);
|
||||
console.log('Memory before load (B):', memoryBeforeLoad);
|
||||
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadAndRelease(1));
|
||||
await page.waitForTimeout(5000); // wait for long enough to let the GC do its job
|
||||
await page.waitForTimeout(5000);
|
||||
const memoryAfterFirstLoad = (await getMetrics(page)).JSHeapUsedSize;
|
||||
console.log('Memory after first load:', memoryAfterFirstLoad);
|
||||
console.log('Memory after first load (B):', memoryAfterFirstLoad);
|
||||
|
||||
await page.evaluate(() => window.E2EControllerAPI.loadAndRelease(2));
|
||||
await page.waitForTimeout(5000);
|
||||
const memoryAfterSecondLoad = (await getMetrics(page)).JSHeapUsedSize;
|
||||
console.log('Memory after second load:', memoryAfterSecondLoad);
|
||||
console.log('Memory after second load (B):', memoryAfterSecondLoad);
|
||||
|
||||
const notLeaking = (memoryAfterSecondLoad <= memoryAfterFirstLoad)
|
||||
|| (memoryAfterSecondLoad - memoryAfterFirstLoad <= MAX_MEMORY_OVERFLOW);
|
||||
expect(notLeaking).toBeTruthy();
|
||||
await page.evaluate(() => window.univer.dispose());
|
||||
await page.waitForTimeout(5000);
|
||||
const memoryAfterDisposingUniver = (await getMetrics(page)).JSHeapUsedSize;
|
||||
console.log('Memory after disposing univer (B):', memoryAfterDisposingUniver);
|
||||
|
||||
const noUnitLeaking = memoryAfterSecondLoad - memoryAfterFirstLoad <= MAX_UNIT_MEMORY_OVERFLOW;
|
||||
expect(noUnitLeaking).toBeTruthy();
|
||||
|
||||
const noUniverLeaking = memoryAfterDisposingUniver - memoryBeforeLoad <= MAX_UNIVER_MEMORY_OVERFLOW;
|
||||
expect(noUniverLeaking).toBeTruthy();
|
||||
});
|
||||
|
||||
interface IMetrics {
|
||||
JSHeapUsedSize: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a performance metric from the chrome cdp session.
|
||||
* Chrome only.
|
||||
* @param {Page} page page to attach cdpClient
|
||||
* @return {IMetrics}
|
||||
* @see {@link https://github.com/microsoft/playwright/issues/18071}
|
||||
*/
|
||||
async function getMetrics(page: Page): Promise<IMetrics> {
|
||||
const client = await page.context().newCDPSession(page);
|
||||
await client.send('Performance.enable');
|
||||
const perfMetricObject = await client.send('Performance.getMetrics');
|
||||
const extractedMetric = perfMetricObject?.metrics;
|
||||
const metricObject = extractedMetric.reduce((acc, { name, value }) => {
|
||||
acc[name] = value;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
return metricObject as unknown as IMetrics;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright 2023-present DreamNum Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Page } from '@playwright/test';
|
||||
|
||||
interface IMetrics {
|
||||
JSHeapUsedSize: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a performance metric from the chrome cdp session.
|
||||
* Chrome only.
|
||||
* @param {Page} page page to attach cdpClient
|
||||
* @return {IMetrics}
|
||||
* @see {@link https://github.com/microsoft/playwright/issues/18071}
|
||||
*/
|
||||
export async function getMetrics(page: Page): Promise<IMetrics> {
|
||||
const client = await page.context().newCDPSession(page);
|
||||
await client.send('Performance.enable');
|
||||
await client.send('HeapProfiler.collectGarbage');
|
||||
const perfMetricObject = await client.send('Performance.getMetrics');
|
||||
const extractedMetric = perfMetricObject?.metrics;
|
||||
const metricObject = extractedMetric.reduce((acc, { name, value }) => {
|
||||
acc[name] = value;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
return metricObject as unknown as IMetrics;
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ import type {
|
||||
} from '@univerjs/engine-render';
|
||||
import { FUniver, toDisposable } from '@univerjs/core';
|
||||
import { IRenderManagerService } from '@univerjs/engine-render';
|
||||
import { FSheetHooks } from '@univerjs/sheets/facade';
|
||||
import { SHEET_VIEW_KEY } from '@univerjs/sheets-ui';
|
||||
import { FSheetHooks } from '@univerjs/sheets/facade';
|
||||
|
||||
export interface IFUniverSheetsUIMixin {
|
||||
/**
|
||||
|
||||
@@ -858,13 +858,14 @@ export class SlideTabBar {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.removeListener();
|
||||
|
||||
this._downActionX = 0;
|
||||
this._moveActionX = 0;
|
||||
this._compareDirection = 0;
|
||||
this._compareIndex = 0;
|
||||
this._slideTabItems = [];
|
||||
this._activeTabItem = null;
|
||||
this.removeListener();
|
||||
|
||||
// TODO@Dushusir: If set to null, the types in other places need to be judged
|
||||
// this._slideTabBar = null;
|
||||
|
||||
@@ -31,6 +31,14 @@ export class ScriptEditorService extends Disposable {
|
||||
super();
|
||||
}
|
||||
|
||||
override dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
if (this._editorInstance) {
|
||||
this._editorInstance.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
setEditorInstance(editor: editor.IStandaloneCodeEditor): IDisposable {
|
||||
this._editorInstance = editor;
|
||||
return toDisposable(() => (this._editorInstance = null));
|
||||
@@ -43,10 +51,7 @@ export class ScriptEditorService extends Disposable {
|
||||
requireVscodeEditor(): void {
|
||||
if (!window.MonacoEnvironment) {
|
||||
const config = this._configService.getConfig<IUniverUniscriptConfig>(UNISCRIPT_PLUGIN_CONFIG_KEY);
|
||||
|
||||
window.MonacoEnvironment = {
|
||||
getWorkerUrl: config?.getWorkerUrl,
|
||||
};
|
||||
window.MonacoEnvironment = { getWorkerUrl: config?.getWorkerUrl };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ export default defineConfig({
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !!process.env.CI,
|
||||
timeout: 30_000,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
|
||||
Reference in New Issue
Block a user