- Open
js-memory-leak.html
in Chrome - Open developer tools and select Profiles tab
- Select Take Heap Snapshot
- Take a base snapshot
- Click Create App five times
- Take another snapshot
- Type in App in the Class Filter
- Notice There are 5 App objects, when there should be just one.
- To find what's causing App objects from being garbage collected, expand App to see the app instances.
- Select any app instance without the yellow background to see the objects retaining the app instance.
- You can see that the app is being retained by an AppEventHandler object.
- Now refresh the page, and check Clear App
- Again repeat steps 3-7.
- You will now notice that the memory leak has been fixed and there is only one App object, regardless of how many times you try to create an app.
Last active
August 29, 2015 14:21
-
-
Save karmadude/a7e1b648682508adb781 to your computer and use it in GitHub Desktop.
How to find JavaScript memory leaks using heap snapshot
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
font: 12px/16px Helvetica, sans-serif; | |
} | |
main { | |
width: 720px; | |
margin: 50px auto; | |
} | |
.app { | |
cursor: pointer; | |
background: #9ddcd7; | |
border: 1px solid #92CDC8; | |
color: #fff; | |
width: 100%; | |
height: 48px; | |
margin: 20px 0; | |
font-size: 20px; | |
font-weight: 500; | |
line-height: 48px; | |
text-align: center; | |
} | |
</style> | |
<main> | |
<div id="test-app"></div> | |
<button id="create-app">Create App</button> | |
<input type="checkbox" id="clear-app"> <label>Clear App</label> | |
| <label>Leaked: <span id="leaked-app-count">0</span></label> | |
</main> | |
<script> | |
var appCount = 0; | |
var app; | |
var createAppButton = document.getElementById("create-app"); | |
var clearAppCheckbox = document.getElementById("clear-app"); | |
var leakedAppCountSpan = document.getElementById("leaked-app-count"); | |
createAppButton.onclick = createApp; | |
function App(id) { | |
this.id = id; | |
this.el = document.getElementById("test-app"); | |
this.el.className = "app"; | |
this.el.textContent = "App " + this.id; | |
this.handler = new AppEventHandler(this); | |
console.log("App " + this.id + " created."); | |
} | |
App.prototype.remove = function(event) { | |
this.el.className = ""; | |
this.handler.remove(); | |
console.log("App " + this.id + " removed."); | |
}; | |
function AppEventHandler(app) { | |
this.app = app; | |
app.el.addEventListener("click", this); | |
} | |
AppEventHandler.prototype.handleEvent = function(event) { | |
console.log(event.type + "ed app " + this.app.id); | |
}; | |
AppEventHandler.prototype.remove = function(event) { | |
this.app.el.removeEventListener("click", this); | |
}; | |
function createApp() { | |
if(clearAppCheckbox.checked) | |
clearApp(); | |
leakedAppCountSpan.textContent = appCount; | |
app = new App(appCount+1); | |
appCount++; | |
} | |
function clearApp() { | |
if(!app) | |
return; | |
app.remove(); | |
app = null; | |
appCount = appCount === 0 ? appCount : appCount - 1; | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment