fix double-freeing remote references
After the page does navigations, garbage collection can still happen in the old context. This commit changes to store references to remote objects by _pages_, instead of by _WebContents_.
This commit is contained in:
parent
9431677e79
commit
adf49daaac
9 changed files with 139 additions and 113 deletions
|
@ -17,16 +17,15 @@ class ObjectsRegistry {
|
|||
|
||||
// Register a new object and return its assigned ID. If the object is already
|
||||
// registered then the already assigned ID would be returned.
|
||||
add (webContents, obj) {
|
||||
add (webContents, contextId, obj) {
|
||||
// Get or assign an ID to the object.
|
||||
const id = this.saveToStorage(obj)
|
||||
|
||||
// Add object to the set of referenced objects.
|
||||
const webContentsId = webContents.getId()
|
||||
let owner = this.owners[webContentsId]
|
||||
let owner = this.owners[contextId]
|
||||
if (!owner) {
|
||||
owner = this.owners[webContentsId] = new Set()
|
||||
this.registerDeleteListener(webContents, webContentsId)
|
||||
owner = this.owners[contextId] = new Set()
|
||||
this.registerDeleteListener(webContents, contextId)
|
||||
}
|
||||
if (!owner.has(id)) {
|
||||
owner.add(id)
|
||||
|
@ -43,25 +42,26 @@ class ObjectsRegistry {
|
|||
}
|
||||
|
||||
// Dereference an object according to its ID.
|
||||
remove (webContentsId, id) {
|
||||
// Dereference from the storage.
|
||||
this.dereference(id)
|
||||
|
||||
// Also remove the reference in owner.
|
||||
let owner = this.owners[webContentsId]
|
||||
// Note that an object may be double-freed (cleared when page is reloaded, and
|
||||
// then garbage collected in old page).
|
||||
remove (contextId, id) {
|
||||
let owner = this.owners[contextId]
|
||||
if (owner) {
|
||||
// Remove the reference in owner.
|
||||
owner.delete(id)
|
||||
// Dereference from the storage.
|
||||
this.dereference(id)
|
||||
}
|
||||
}
|
||||
|
||||
// Clear all references to objects refrenced by the WebContents.
|
||||
clear (webContentsId) {
|
||||
let owner = this.owners[webContentsId]
|
||||
clear (contextId) {
|
||||
let owner = this.owners[contextId]
|
||||
if (!owner) return
|
||||
|
||||
for (let id of owner) this.dereference(id)
|
||||
|
||||
delete this.owners[webContentsId]
|
||||
delete this.owners[contextId]
|
||||
}
|
||||
|
||||
// Private: Saves the object into storage and assigns an ID for it.
|
||||
|
@ -92,12 +92,12 @@ class ObjectsRegistry {
|
|||
}
|
||||
|
||||
// Private: Clear the storage when webContents is reloaded/navigated.
|
||||
registerDeleteListener (webContents, webContentsId) {
|
||||
registerDeleteListener (webContents, contextId) {
|
||||
const processId = webContents.getProcessId()
|
||||
const listener = (event, deletedProcessId) => {
|
||||
if (deletedProcessId === processId) {
|
||||
webContents.removeListener('render-view-deleted', listener)
|
||||
this.clear(webContentsId)
|
||||
this.clear(contextId)
|
||||
}
|
||||
}
|
||||
webContents.on('render-view-deleted', listener)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue