mirror of
https://github.com/eigent-ai/eigent.git
synced 2026-05-19 07:59:39 +00:00
update
This commit is contained in:
parent
c2dc0d2f8a
commit
9ce50205ef
2 changed files with 156 additions and 19 deletions
|
|
@ -51,6 +51,13 @@ findAvailablePort(browser_port).then(port => {
|
|||
app.commandLine.appendSwitch('remote-debugging-port', port + '');
|
||||
});
|
||||
|
||||
// Memory optimization settings
|
||||
app.commandLine.appendSwitch('js-flags', '--max-old-space-size=4096');
|
||||
app.commandLine.appendSwitch('force-gpu-mem-available-mb', '512');
|
||||
app.commandLine.appendSwitch('max_old_space_size', '4096');
|
||||
app.commandLine.appendSwitch('enable-features', 'MemoryPressureReduction');
|
||||
app.commandLine.appendSwitch('renderer-process-limit', '8');
|
||||
|
||||
// ==================== app config ====================
|
||||
process.env.APP_ROOT = MAIN_DIST;
|
||||
process.env.VITE_PUBLIC = VITE_PUBLIC;
|
||||
|
|
@ -922,8 +929,8 @@ async function createWindow() {
|
|||
fileReader = new FileReader(win);
|
||||
webViewManager = new WebViewManager(win);
|
||||
|
||||
// create multiple webviews
|
||||
for (let i = 1; i <= 8; i++) {
|
||||
// create initial webviews (reduced from 8 to 3)
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
webViewManager.createWebview(i === 1 ? undefined : i.toString());
|
||||
}
|
||||
|
||||
|
|
@ -1197,14 +1204,24 @@ const cleanupPythonProcess = async () => {
|
|||
const pid = python_process.pid;
|
||||
log.info('Cleaning up Python process', { pid });
|
||||
|
||||
// Remove all listeners to prevent memory leaks
|
||||
python_process.removeAllListeners();
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
kill(pid, 'SIGINT', (err) => {
|
||||
kill(pid, 'SIGTERM', (err) => {
|
||||
if (err) {
|
||||
log.error('Failed to clean up process tree:', err);
|
||||
log.error('Failed to clean up process tree with SIGTERM:', err);
|
||||
// Try SIGKILL as fallback
|
||||
kill(pid, 'SIGKILL', (killErr) => {
|
||||
if (killErr) {
|
||||
log.error('Failed to force kill process tree:', killErr);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
} else {
|
||||
log.info('Successfully cleaned up Python process tree');
|
||||
resolve();
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -1224,17 +1241,38 @@ const cleanupPythonProcess = async () => {
|
|||
}
|
||||
}
|
||||
|
||||
// Clean up any temporary files in userData
|
||||
try {
|
||||
const tempFiles = ['backend.lock', 'uv_installing.lock'];
|
||||
for (const file of tempFiles) {
|
||||
const filePath = path.join(userData, file);
|
||||
if (fs.existsSync(filePath)) {
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
log.error('Error cleaning up temp files:', error);
|
||||
}
|
||||
|
||||
python_process = null;
|
||||
} catch (error) {
|
||||
log.error('Error occurred while cleaning up process:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// brefore close
|
||||
// before close
|
||||
const handleBeforeClose = () => {
|
||||
let isQuitting = false;
|
||||
|
||||
app.on('before-quit', () => {
|
||||
isQuitting = true;
|
||||
});
|
||||
|
||||
win?.on("close", (event) => {
|
||||
event.preventDefault();
|
||||
win?.webContents.send("before-close");
|
||||
if (!isQuitting) {
|
||||
event.preventDefault();
|
||||
win?.webContents.send("before-close");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1289,8 +1327,15 @@ app.whenReady().then(() => {
|
|||
// ==================== window close event ====================
|
||||
app.on('window-all-closed', () => {
|
||||
log.info('window-all-closed');
|
||||
webViewManager = null;
|
||||
|
||||
// Clean up WebView manager
|
||||
if (webViewManager) {
|
||||
webViewManager.destroy();
|
||||
webViewManager = null;
|
||||
}
|
||||
|
||||
win = null;
|
||||
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
|
|
@ -1310,12 +1355,44 @@ app.on('activate', () => {
|
|||
});
|
||||
|
||||
// ==================== app exit event ====================
|
||||
app.on('before-quit', () => {
|
||||
app.on('before-quit', async (event) => {
|
||||
log.info('before-quit');
|
||||
log.info('quit python_process.pid: ' + python_process?.pid);
|
||||
if (win) {
|
||||
win.destroy();
|
||||
|
||||
// Prevent default quit to ensure cleanup completes
|
||||
event.preventDefault();
|
||||
|
||||
try {
|
||||
// Clean up resources
|
||||
if (webViewManager) {
|
||||
webViewManager.destroy();
|
||||
webViewManager = null;
|
||||
}
|
||||
|
||||
if (win && !win.isDestroyed()) {
|
||||
win.destroy();
|
||||
win = null;
|
||||
}
|
||||
|
||||
// Wait for Python process cleanup
|
||||
await cleanupPythonProcess();
|
||||
|
||||
// Clean up file reader if exists
|
||||
if (fileReader) {
|
||||
fileReader = null;
|
||||
}
|
||||
|
||||
// Clear any remaining timeouts/intervals
|
||||
if (global.gc) {
|
||||
global.gc();
|
||||
}
|
||||
|
||||
log.info('All cleanup completed, exiting...');
|
||||
} catch (error) {
|
||||
log.error('Error during cleanup:', error);
|
||||
} finally {
|
||||
// Force quit after cleanup
|
||||
app.exit(0);
|
||||
}
|
||||
cleanupPythonProcess();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ export class WebViewManager {
|
|||
private webViews = new Map<string, WebViewInfo>()
|
||||
private win: BrowserWindow | null = null
|
||||
private size: Size = { x: 0, y: 0, width: 0, height: 0 }
|
||||
private maxInactiveWebviews = 5
|
||||
private lastCleanupTime = Date.now()
|
||||
|
||||
constructor(window: BrowserWindow) {
|
||||
this.win = window
|
||||
}
|
||||
|
|
@ -63,6 +66,12 @@ export class WebViewManager {
|
|||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true,
|
||||
backgroundThrottling: true,
|
||||
offscreen: false,
|
||||
sandbox: true,
|
||||
disableBlinkFeatures: 'Accelerated2dCanvas',
|
||||
enableBlinkFeatures: 'IdleDetection',
|
||||
autoplayPolicy: 'document-user-activation-required',
|
||||
},
|
||||
})
|
||||
view.webContents.on('did-finish-load', () => {
|
||||
|
|
@ -119,13 +128,22 @@ export class WebViewManager {
|
|||
webViewInfo.view.setBounds({ x: -1919, y: -1079, width: 1920, height: 1080 })
|
||||
const activeSize = this.getActiveWebview().length
|
||||
const allSize = Array.from(this.webViews.values()).length
|
||||
if (allSize - activeSize <= 3) {
|
||||
const inactiveSize = allSize - activeSize
|
||||
|
||||
// Clean up inactive webviews if too many
|
||||
if (inactiveSize > this.maxInactiveWebviews && Date.now() - this.lastCleanupTime > 30000) {
|
||||
this.cleanupInactiveWebviews()
|
||||
this.lastCleanupTime = Date.now()
|
||||
}
|
||||
|
||||
// Create new webviews if needed
|
||||
if (inactiveSize <= 2) {
|
||||
const existingKeys = Array.from(this.webViews.keys()).map(Number).filter(n => !isNaN(n))
|
||||
const maxId = existingKeys.length > 0 ? Math.max(...existingKeys) : 0
|
||||
const startId = maxId + 1
|
||||
|
||||
// Create webviews sequentially to avoid race conditions
|
||||
for (let i = 0; i < 3; i++) {
|
||||
// Create only 2 new webviews to reduce memory usage
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const nextId = (startId + i).toString()
|
||||
this.createWebview(nextId, 'about:blank?use=0')
|
||||
}
|
||||
|
|
@ -190,6 +208,10 @@ export class WebViewManager {
|
|||
let newId = Number(id)
|
||||
webViewInfo.view.setBounds({ x: -9999 + newId * 100, y: -9999 + newId * 100, width: 100, height: 100 })
|
||||
webViewInfo.isShow = false
|
||||
|
||||
if (webViewInfo.view.webContents && !webViewInfo.view.webContents.isDestroyed()) {
|
||||
webViewInfo.view.webContents.setBackgroundThrottling(true)
|
||||
}
|
||||
|
||||
return { success: true }
|
||||
}
|
||||
|
|
@ -198,19 +220,36 @@ export class WebViewManager {
|
|||
let newId = Number(webview.id)
|
||||
webview.view.setBounds({ x: -9999 + newId * 100, y: -9999 + newId * 100, width: 100, height: 100 })
|
||||
webview.isShow = false
|
||||
|
||||
if (webview.view.webContents && !webview.view.webContents.isDestroyed()) {
|
||||
webview.view.webContents.setBackgroundThrottling(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public showWebview(id: string) {
|
||||
const webViewInfo = this.webViews.get(id)
|
||||
public async showWebview(id: string) {
|
||||
let webViewInfo = this.webViews.get(id)
|
||||
|
||||
// If webview doesn't exist, create it
|
||||
if (!webViewInfo) {
|
||||
return { success: false, error: `Webview with id ${id} not found` }
|
||||
console.log(`Webview ${id} not found, creating new one`)
|
||||
const createResult = await this.createWebview(id, 'about:blank?use=0')
|
||||
if (!createResult.success) {
|
||||
return { success: false, error: `Failed to create webview ${id}` }
|
||||
}
|
||||
webViewInfo = this.webViews.get(id)!
|
||||
}
|
||||
|
||||
const currentUrl = webViewInfo.view.webContents.getURL();
|
||||
this.win?.webContents.send("url-updated", currentUrl);
|
||||
webViewInfo.isShow = true
|
||||
this.changeViewSize(id, this.size)
|
||||
console.log("showWebview", id, this.size)
|
||||
|
||||
if (webViewInfo.view.webContents && !webViewInfo.view.webContents.isDestroyed()) {
|
||||
webViewInfo.view.webContents.setBackgroundThrottling(false)
|
||||
}
|
||||
|
||||
if (this.win && !this.win.isDestroyed()) {
|
||||
this.win.webContents.send('webview-show', id)
|
||||
}
|
||||
|
|
@ -228,6 +267,14 @@ export class WebViewManager {
|
|||
return { success: false, error: `Webview with id ${id} not found` }
|
||||
}
|
||||
|
||||
if (!webViewInfo.view.webContents.isDestroyed()) {
|
||||
webViewInfo.view.webContents.removeAllListeners()
|
||||
webViewInfo.view.webContents.session.clearCache()
|
||||
webViewInfo.view.webContents.session.clearStorageData({
|
||||
storages: ['cookies', 'localstorage', 'websql', 'indexdb', 'serviceworkers', 'cachestorage']
|
||||
})
|
||||
}
|
||||
|
||||
// remove webview from parent container
|
||||
if (this.win?.contentView) {
|
||||
this.win.contentView.removeChildView(webViewInfo.view)
|
||||
|
|
@ -254,5 +301,18 @@ export class WebViewManager {
|
|||
})
|
||||
this.webViews.clear()
|
||||
}
|
||||
|
||||
private cleanupInactiveWebviews() {
|
||||
const inactiveWebviews = Array.from(this.webViews.entries())
|
||||
.filter(([id, info]) => !info.isActive && !info.isShow && info.currentUrl === 'about:blank?use=0')
|
||||
.sort((a, b) => parseInt(a[0]) - parseInt(b[0]))
|
||||
|
||||
const toRemove = inactiveWebviews.slice(this.maxInactiveWebviews)
|
||||
|
||||
toRemove.forEach(([id, _]) => {
|
||||
console.log(`Cleaning up inactive webview: ${id}`)
|
||||
this.destroyWebview(id)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue