在此 Windows 小工具中查找导致内存泄漏的原因
Find what is causing a memory leak in this Windows Gadget
场景
我正在将Windows小工具平台与此小工具一起使用:
http://win7gadgets.com/pc-system/sushis_driveinfo.html
该小工具问题
有内存泄漏,如果我继续运行这个小工具+24小时。 它可以将RAM消耗增加到1 GB,而其他类似的小工具不会证明这一点,所以我丢弃了这是一个侧边栏.exe 内存管理不是脚本错误。
当运行小工具的时间更长时,小工具的无响应性会更多(单击时(。
我对 JavaScript 的了解是 NULL,但无论如何我可以理解语法并尝试理解开发人员在此代码中正在做什么,我认为问题在于管理图像对象时,但在我看来,这些对象似乎在每次操作后都得到了适当的处理。
问题
这是小工具源。
有人可以帮助我发现并修复导致此小工具内存泄漏的原因吗?
sushi_driveinfo.html(主窗口(:
<html>
<head>
<title>Drive Info</title>
<style>
body { margin: 0; padding: 0; width: 156px; height: 200px; background-image: url(images'canvas.png); color: #ffffff; font-family: 'Segoe UI'; }
#targets { position: absolute; top: 0; left: 0; }
.target { position: absolute; width: 156px; height: 48; left: 0; cursor: hand; }
</style>
<script type="text/javascript">
var lst = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var timeout = null;
var drives = new Array(26);
var drvchk = new Array(26);
var drvspc = new Array(26);
var vizchg = false;
var current_y = 0;
var background,theme,remove,local,network,media,show_pc,show_net;
var item_height=48;
var icon_offset=20;
var text_offset=72;
var meter_offset=24;
function convertBytes(b)
{
var i = 0, u = Array(' MB', ' GB', ' TB');
while (b >= 1024 && (b /= 1024) >= 1) i++;
return (Math.round(b * 100) / 100) + u[i];
}
function openDrive()
{
var d = window.event.srcElement.getAttribute('drive');
System.Shell.execute(d + ':''');
return;
}
function openNetwork()
{
System.Shell.execute("Explorer", "/N,::{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}");
return;
}
function openComputer()
{
System.Shell.execute("Explorer", "/N,::{20D04FE0-3AEA-1069-A2D8-08002B30309D}");
return;
}
function recheckDrives() {
for(var i = 0; i < 26; i++)
{
if (!drives[i]) {
drives[i] = System.Shell.drive(lst.charAt(i));
if (drives[i]) { vizchg = true; drvchk[i] = true; }
} else {
if (drives[i].isReady != drvchk[i]) { drvchk[i] = !drvchk[i]; vizchg = true; }
if (drives[i].isReady && drives[i].freeSpace != drvspc[i]) { drvspc[i] = drives[i].freeSpace; vizchg = true; }
}
}
}
function calcHeight(h) {
var y=0;
if(show_pc==2) y+=h;
if(show_net==2) y+=h;
for(var i=0;i<26;i++)
if(isDriveVisible(i)) y+=h;
return y;
}
function isDriveVisible(i) {
if(drvchk[i]) {
if (drives[i].driveType == 2 && remove == 1) ;
else if (drives[i].driveType == 3 && local == 1) ;
else if (drives[i].driveType == 4 && network == 1) ;
else if (drives[i].driveType == 5 && media == 1) ;
else if (drives[i].driveType == 1 || drives[i].driveType == 6) ;
else
return true;
}
return false;
}
function paintPC() {
if (show_pc == 2) {
canvas.addImageObject('images/backgrounds/background' + background + 's.png', 0, current_y);
var di=canvas.addImageObject('images/drives/pc'+ theme +'.png', icon_offset, current_y);
di.width*=0.8;
di.height*=0.8;
canvas.addTextObject('Computer', 'Segoe UI', 11, 'white', text_offset, current_y + 5);
var b = document.createElement('DIV');
b.className = 'target';
b.style.posTop = current_y;
b.onclick = openComputer;
targets.appendChild(b);
current_y+=item_height;
}
return;
}
function paintNET() {
if (show_net == 2) {
canvas.addImageObject('images/backgrounds/background' + background + 's.png', 0, current_y);
var di=canvas.addImageObject('images/drives/net'+ theme +'.png', icon_offset, current_y);
di.width*=0.8;
di.height*=0.8;
canvas.addTextObject('Network', 'Segoe UI', 11, 'white', text_offset, current_y + 5);
var b = document.createElement('DIV');
b.className = 'target';
b.style.posTop = current_y;
b.onclick = openNetwork;
targets.appendChild(b);
current_y+=item_height;
}
return;
}
function paintGadget()
{
try {
recheckDrives();
if (!vizchg) return;
var total_height=calcHeight(item_height);
System.Gadget.beginTransition();
document.body.style.height=total_height;
canvas.style.height=total_height;
canvas.removeObjects();
targets.innerHtml = '';
current_y = 0;
paintPC();
paintNET();
for(i = 0; i < 26; i++)
{
if(isDriveVisible(i)) {
if (drives[i].freeSpace != 0) {
canvas.addImageObject('images/backgrounds/background' + background + '.png', 0, current_y);
var f = Math.round(drives[i].freeSpace / drives[i].totalSize * 100);
var u = (100 - f);
canvas.addTextObject(convertBytes(drives[i].freeSpace) + ' / ' + f + '%', 'Segoe UI', 10, 'white', text_offset, current_y + 17);
var m = canvas.addImageObject('images/meter' + (u < 90 ? 'blue': (u < 98 ? 'orange': 'red')) + '.png', meter_offset, current_y + 34);
m.width = Math.floor((u * 128 / 100));
m.left = 24 - Math.floor(((128 - m.width) / 2));
} else {
canvas.addImageObject('images/backgrounds/background' + background + 's.png', 0, current_y);
canvas.addTextObject(convertBytes(drives[i].totalSize), 'Segoe UI', 10, 'white', text_offset, current_y + 17);
}
var di=canvas.addImageObject('images/drives/drive' + drives[i].driveType + theme + '.png', icon_offset, current_y-5);
di.width*=0.8;
di.height*=0.8;
canvas.addTextObject(drives[i].volumeLabel + ' (' + drives[i].driveLetter + ':)', 'Segoe UI', 11, 'white', text_offset, current_y + 5);
var o = document.createElement('DIV');
o.className = 'target';
o.style.posTop = current_y;
o.setAttribute('drive', drives[i].driveLetter);
o.onclick = openDrive;
targets.appendChild(o);
current_y += item_height;
}
System.Gadget.endTransition(System.Gadget.TransitionType.morph,0.1);
window.setTimeout(fixCanvasBackground, 600);
}
} finally {
vizchg = false;
return;
}
}
function fixCanvasBackground() {
canvas.src = canvas.src;
}
function initDrives()
{
for(var i = 0; i < 26; i++) {
drives[i] = System.Shell.drive(lst.charAt(i));
if (drives[i] && drives[i].isReady)
{ drvchk[i] = true ; drvspc[i] = drives[i].freeSpace; }
else { drvchk[i] = false; }
}
return;
}
function onShowSettings() {
window.clearInterval(timeout);
System.Gadget.beginTransition();
window.setTimeout(endTransitionFast, 400);
}
function onSettingsClosed() {
readSettings();
timeout=window.setInterval(paintGadget, 2500);
vizchg=true;
paintGadget();
}
function endTransitionFast() {
System.Gadget.endTransition(System.Gadget.TransitionType.morph, 0.1);
fixCanvasBackground();
}
function readSettings() {
background=System.Gadget.Settings.read("background");
if(background==0) { background=2; System.Gadget.Settings.write("background",2); }
theme=System.Gadget.Settings.read("theme");
if(theme==0) { theme=1; System.Gadget.Settings.write("theme",1); }
show_pc=System.Gadget.Settings.read("showpc");
if(show_pc==0) { show_pc=1; System.Gadget.Settings.write("showpc",1); }
show_net=System.Gadget.Settings.read("shownet");
if(show_net==0) { show_net=1; System.Gadget.Settings.write("shownet",1); }
local=System.Gadget.Settings.read("local");
if(local==0) { local=2; System.Gadget.Settings.write("local",2); }
media=System.Gadget.Settings.read("media");
if(media==0) { media=2; System.Gadget.Settings.write("media",2); }
network=System.Gadget.Settings.read("network");
if(network==0) { network=2; System.Gadget.Settings.write("network",2); }
remove=System.Gadget.Settings.read("remove");
if(remove==0) { remove=2; System.Gadget.Settings.write("remove",2); }
}
function onLoad()
{
System.Gadget.settingsUI = "settings.html";
System.Gadget.onSettingsClosed = onSettingsClosed;
System.Gadget.onShowSettings = onShowSettings;
readSettings();
initDrives();
timeout = window.setInterval(paintGadget, 2500);
vizchg = true;
paintGadget();
return;
}
</script>
</head>
<body onload="onLoad()">
<div id="targets"></div>
<g:background id="canvas" src="images/canvas.png" style="position: absolute; top: 0; left: 0; width: 156; height: 200; z-index: -999;" opacity="0" />
</body>
</html>
设置.html(设置窗口(:
<html>
<head>
<style>
body { width: 250px; height: 800px; padding: 0px; margin: 0px; font-family: Tahoma; }
body,p,div,span,td { font-size: 9pt; }
label { font-weight: bold; }
input,select { font: Arial; font-size: 9pt; }
table { width: 100%; }
</style>
<script>
var background, maxBackgrounds = 3, theme = 1, maxThemes = 7;
function updateBackground()
{
var x = 84, y = 47, m;
canvas.removeObjects();
canvas.addImageObject('images/backgrounds/background' + background + '.png', x, y);
m = canvas.addImageObject('images/meterblue.png', x + 24, y + 34);
m.width = (0.25 * 128);
m.left = x + 24 - ((128 - m.width) / 2);
canvas.addImageObject('images/drives/drive3' + theme + '.png', x, y);
canvas.addTextObject('Vista (C:)', 'Segoe UI', 11, 'white', x + 58, y + 5);
canvas.addTextObject('40GB / 75%', 'Segoe UI', 10, 'white', x + 58, y + 17);
//y -= 20;
//canvas.addImageObject('images/backgrounds/background' + background + '.png', x, y);
//m = canvas.addImageObject('images/meterorange.png', x + 24, y + 34);
//m.width = (0.937 * 128);
//m.left = x + 24 - ((128 - m.width) / 2);
//canvas.addImageObject('images/drives/drive3.png', x, y);
//canvas.addTextObject('Apps (D:)', 'Segoe UI', 11, 'white', x + 58, y + 5);
//canvas.addTextObject('10GB / 6.3%', 'Segoe UI', 10, 'white', x + 58, y + 17);
canvas.addImageObject('images/drives/drive3' + theme + '.png', x-85, y+130);
canvas.addImageObject('images/drives/drive2' + theme + '.png', x-85, y+172);
canvas.addImageObject('images/drives/drive4' + theme + '.png', x-85, y+215);
canvas.addImageObject('images/drives/drive5' + theme + '.png', x-85, y+258);
}
function onBackground()
{
var e = window.event, o = e.srcElement, b = o.getAttribute('base');
o.src = 'images/settings/' + b + (e.type == 'mouseover' || e.type == 'mouseup' ? 'hover': (e.type == 'mousedown' ? 'pressed': '')) + '.png';
if (e.type == 'mouseup')
{
if (b == 'next') background++; else background--;
if (background < 1) background = maxBackgrounds;
if (background > maxBackgrounds) background = 1;
updateBackground();
}
}
function onTheme()
{
var e = window.event, o = e.srcElement, b = o.getAttribute('base');
o.src = 'images/settings/' + b + (e.type == 'mouseover' || e.type == 'mouseup' ? 'hover': (e.type == 'mousedown' ? 'pressed': '')) + '.png';
if (e.type == 'mouseup')
{
if (b == 'next') theme++; else theme--;
if (theme < 1) theme = maxThemes;
if (theme > maxThemes) theme = 1;
updateBackground();
}
}
function onClose(event)
{
if (event.closeAction == event.Action.commit)
{
System.Gadget.Settings.write("background", background);
System.Gadget.Settings.write("theme", theme);
System.Gadget.Settings.write("showpc", document.boxes.mypc.checked ? 2 : 1);
System.Gadget.Settings.write("shownet", document.boxes.netw.checked ? 2 : 1);
System.Gadget.Settings.write("remove", document.boxes.remove.checked ? 2 : 1);
System.Gadget.Settings.write("local", document.boxes.local.checked ? 2 : 1);
System.Gadget.Settings.write("network", document.boxes.network.checked ? 2 : 1);
System.Gadget.Settings.write("media", document.boxes.media.checked ? 2 : 1);
}
event.cancel = false;
// System.Gadget.beginTransition();
// window.setTimeout(endtransit, 400);
}
/* function endtransit() {
System.Gadget.endTransition(System.Gadget.TransitionType.morph, 0.1);
}*/
function onLoad()
{
var box;
System.Gadget.onSettingsClosing = onClose;
background = System.Gadget.Settings.read("background");
if (background == 0) background = 2;
theme = System.Gadget.Settings.read("theme");
if (theme == 0) theme = 1;
System.Gadget.Settings.read("remove") == 2 ? document.boxes.remove.checked = true : false;
System.Gadget.Settings.read("local") == 2 ? document.boxes.local.checked = true : false;
System.Gadget.Settings.read("network") == 2 ? document.boxes.network.checked = true : false;
System.Gadget.Settings.read("media") == 2 ? document.boxes.media.checked = true : false;
System.Gadget.Settings.read("showpc") == 2 ? document.boxes.mypc.checked = true : false;
System.Gadget.Settings.read("shownet") == 2 ? document.boxes.netw.checked = true : false;
updateBackground();
}
</script>
</head>
<body onload="onLoad()">
<g:background id="canvas" src="images/settings/desktop.png" style="position: absolute; left: 1; top: 1; z-index: -999;" />
<div style="position: absolute; left: 0; top: 147px;">
<table cellspacing="0" cellpadding="0">
<tr>
<td style="width: 33%; padding-right: 10px;" align="right"><img src="images/settings/previous.png" base="previous" style="cursor: hand;" onmouseover="onBackground();" onmouseout="onBackground();" onmousedown="onBackground();" onmouseup="onBackground();" /></td>
<td style="width: 33%;" align="center"><label>Backgrounds</label></td>
<td style="width: 33%; padding-left: 10px;" align="left"><img src="images/settings/next.png" base="next" style="cursor: hand;" onmouseover="onBackground();" onmouseout="onBackground();" onmousedown="onBackground();" onmouseup="onBackground();" /></td>
</tr>
<tr>
<td style="width: 33%; padding-right: 10px;" align="right"><img src="images/settings/previous.png" base="previous" style="cursor: hand;" onmouseover="onTheme();" onmouseout="onTheme();" onmousedown="onTheme();" onmouseup="onTheme();" /></td>
<td style="width: 33%;" align="center"><label>Icon Theme</label></td>
<td style="width: 33%; padding-left: 10px;" align="left"><img src="images/settings/next.png" base="next" style="cursor: hand;" onmouseover="onTheme();" onmouseout="onTheme();" onmousedown="onTheme();" onmouseup="onTheme();" /></td>
</tr>
</table>
<table cellspacing="0" cellpadding="0" style="margin-top: 15px;margin-left:60px;">
<tr><td>
<form name="boxes">
<input type="checkbox" name="local">
<font style="font-size: 8pt;">Local Drives</font><p>
<input type="checkbox" name="remove">
<font style="font-size: 8pt;">Removable Drives</font><p>
<input type="checkbox" name="network">
<font style="font-size: 8pt;">Network Drives</font><p>
<input type="checkbox" name="media">
<font style="font-size: 8pt;">Media Drives</font><p>
<input type="checkbox" name="mypc">
<font style="font-size: 8pt;">My Computer link</font><br>
<input type="checkbox" name="netw">
<font style="font-size: 8pt;">Network Link</font>
</form>
</td></tr>
</table>
</div>
</body>
</html>
更新:
如果有帮助,这是完整的小工具来源:
https://www.mediafire.com/?c8h1271714sp6tz
系统上安装的驱动程序之一总是有可能泄漏导致此问题。但是,在查看该 JavaScript 代码时,有一种模式在过去引起了问题,现在有了解决方案。
小工具的主循环如下所示:
function paintGadget() {
// repaint/rebuild all UI elelments
// remove all elements
targets.innerHtml = '';
// buildup
var o = document.createElement('DIV');
o.onclick = openDrive;
targets.appendChild(o);
}
function openDrive() {
}
window.setInterval(paintGadget, 2500);
这基本上意味着:每2.5秒调用一次paintGadget,永远
如果 javascript 引擎及其资源不再在任何范围内时被垃圾回收,这应该没问题。在这里,由于草率的编程,事情可能会变得糟糕。
根据用户 dsg 的回答,我们了解到事件侦听器是垃圾回收失败的根本原因。
为了克服这个问题,我们必须将函数paintGadget
中的行targets.innerHtml = '';
替换为一个实现,该实现在删除元素本身之前删除每个元素上的事件处理程序,如下所示:
while(targets.firstChild) {
var ch = targets.firstChild;
ch.onclick = null;
targets.removeChild(ch);
}
如介绍中所述,paintGadget 在画布上做得更多,它遵循类似的模式,删除所有内容并重新创建。如果那里有泄漏,也需要重新实现。
- 重复应用 d3 转换导致的内存泄漏
- IE7中的blockUI插件内存泄漏25kb
- Javascript闭包-如何防止内存泄漏
- jQuery Draggable:内存泄漏
- "检测到可能的EventEmitter内存泄漏”;使用Gulp+Watchify+Factor捆绑包
- 在Dojo类中递归调用setTimeout时是否存在内存泄漏
- 是内存泄漏
- 将处理程序留在img.onload上是内存泄漏
- 具有并发sse连接的node.js内存泄漏
- 简单对象的Javascript内存泄漏
- WeakMap是否会将我从父/子关系的内存泄漏中拯救出来
- Javascript绘制画布内存泄漏
- 为什么我的svg节点在IE中泄漏内存
- AngularJS指令包装器与Kendo一起泄漏内存
- 经过几次清理尝试后,主干仍在泄漏内存
- 这个js代码如何泄漏内存
- 未处理的postMessage是否泄漏内存
- 动态创建和销毁三.js场景,而不会泄漏内存
- 我的PyV8上下文泄漏内存
- 为什么我的数字时钟功能泄漏内存