想想,每天使用者与您的网站可视化时,他们单厢建立捷伊第一类、变量和表达式。如果您不留神,这些第一类可能会熔解,堵塞应用程序的缓存并降低整座使用者新体验。这就像信息公路上的拥堵,两个令人懊恼的困局,能让使用者却步。
但它不一定是这样的。凭借着正确的科学知识和控制技术,您能控制您的 JavaScript 缓存并升用的插件平稳高效率地运行。
在今天的该文中,我们将深入探讨 JavaScript 缓存管理工作的原委,包括缓存外泄的常用其原因以及防止它的策略。无论您是专业的还是初学者JavaScript开发者,您单厢对怎样撰写简化、平均和加速的标识符有更深入的介绍。
介绍 JavaScript 缓存管理工作
1.废弃物过滤器
JavaScript 发动机采用废弃物过滤器来释放出来无须采用的内存。废弃物过滤器的工作是辨识并删掉插件无须采用的第一类。它透过持续监视标识符中的第一类和表达式,并追踪什么样第一类和表达式仍在被提及来实现这一点儿。一旦两个第一类无须被采用,废弃物过滤器将其记号为删掉并释放出来它正在采用的缓存。
废弃物过滤器采用一种称为“记号和去除”的控制技术来管理工作缓存。它首先记号大部份仍在采用的第一类,然后“扫到”堆并删掉大部份未记号的第一类。这个过程会不定期展开,并且在堆缓存不足时展开,以保证插件的缓存采用始终尽量高效率。
2.栈与堆
当谈及 JavaScript 中的缓存时,有两个主要参加者:栈和堆。
栈用作储存仅在表达式执行期间须要的统计数据。它加速高效率,但耗电量有限。当两个表达式被初始化时,JavaScript 发动机将表达式的表达式和模块填充栈,当表达式回到时,它再次将它弹出。栈用作加速出访和加速缓存管理工作。
另一方面,堆用作储存插件整座开发周期所需的统计数据。它比栈慢一点儿,计划性还好儿,但耗电量小得多。堆用作储存第一类、字符串和其他须要多次出访的复杂计算机程序。
缓存外泄的常用其原因
您很清楚缓存外泄可能是两个将错就错的敌人,它会逃出您的插件并导致操控性问题。透过介绍缓存外泄的常用其原因,您能用击败它所需的科学知识民兵组织自己。
1.循环提及
缓存外泄的最常用其原因之一是循环提及。当两个或多个第一类相互提及时,就会发生这种情况,从而形成废弃物过滤器无法破坏的循环。这可能会导致第一类在无须须要后很长时间内仍保留在缓存中。
这是示例:
let object1 = {};let object2 = {};// create a circular reference between object1 and object2object1.next = object2;object2.prev = object1;// do something with object1 and object2// …// set object1 and object2 to null to break the circular referenceobject1 = null;object2 = null;
在此示例中,我们建立了两个第一类,object1 和 object2,并透过向它添加 next 和 prev 属性在它之间建立循环提及。
然后,我们将 object1 和 object2 设置为 null 以打破循环提及,但由于废弃物过滤器无法打破循环提及,因此第一类将在无须须要后很长时间内保留在缓存中,从而导致缓存外泄。
为了防止这种类型的缓存外泄,我们能采用一种称为“手动缓存管理工作”的控制技术,透过采用 JavaScript 的 delete 关键字来删掉建立循环提及的属性。
delete object1.next;delete object2.prev;
防止此类缓存外泄的另一种方法是采用 WeakMap 和 WeakSet,它允许您建立对对象和表达式的弱提及,您能在本文后面阅读有关此选项的更多信息。
2.事件监听器
缓存外泄的另两个常用其原因是事件监听器,当您将事件侦听器附加到元素时,它会建立对侦听器表达式的提及,该表达式能防止废弃物过滤器释放出来元素采用的缓存。如果在无须须要该元素时未删掉侦听器表达式,这可能会导致缓存外泄。
我们一起来看两个例子:
let button = document.getElementById(“my-button”);// attach an event listener to the buttonbutton.addEventListener(“click”, function() { console.log(“Button was clicked!”);});// do something with the button// …// remove the button from the DOMbutton.parentNode.removeChild(button);
在此示例中,我们将事件侦听器附加到按钮元素,然后从 DOM 中删掉该按钮。即使按钮元素无须存在于文档中,事件侦听器仍附加到它,这会建立对侦听器表达式的提及,以防止废弃物过滤器释放出来该元素采用的缓存。如果在无须须要该元素时未删掉侦听器表达式,这可能会导致缓存外泄。
为防止此类缓存外泄,在无须须要该元素时删掉事件侦听器很重要:
button.removeEventListener(“click”, function() { console.log(“Button was clicked!”);});
另一种方法是采用 EventTarget.removeAllListeners() 方法删掉大部份已添加到特定事件目标的事件侦听器。
button.removeAllListeners();
3.全局表达式
缓存外泄的第三个常用其原因是全局表达式。当您建立全局变量时,能从标识符中的任何位置出访它,这使得很难确定何时无须须要它。这可能会导致表达式在无须须要后很长时间仍保留在缓存中。这是两个例子:
// create a global variablelet myData = { largeArray: new Array(1000000).fill(“some data”), id: 1};// do something with myData// …// set myData to null to break the referencemyData = null;
在这个例子中,我们建立了两个全局表达式 myData 并在其中储存了大量统计数据。
然后我们将 myData 设置为 null 以中断提及,但是由于该表达式是全局表达式,它仍然能从您的标识符中的任何位置出访,并且很难确定何时无须须要它,这会导致该表达式在缓存中保留很长时间 在无须须要它之后,导致缓存泄漏。
为防止这种类型的缓存外泄,您能采用“表达式作用域”控制技术。它涉及建立两个表达式并在该表达式内声明表达式,以便它只能在表达式范围内出访。这样,当无须须要该表达式时,表达式会自动被废弃物回收。
function myFunction() { let myData = { largeArray: new Array(1000000).fill(“some data”), id: 1 }; // do something with myData // …}myFunction();
另一种方法是采用 JavaScript 的 let 和 const 代替 var,这允许您建立块范围的表达式。用 let 和 const 声明的表达式只能在定义它的块内出访,并且当它超出范围时将被自动废弃物收集。
{ let myData = { largeArray: new Array(1000000).fill(“some data”), id: 1 }; // do something with myData // …}
手动缓存管理工作的最佳实践
JavaScript 提供了缓存管理工作工具和控制技术,能帮助您控制插件的缓存采用情况。
1.采用弱提及
JavaScript 中最强大的缓存管理工作工具之一是 WeakMap 和 WeakSet。这些是特殊的计算机程序,允许您建立对第一类和表达式的弱提及。
弱提及不同于常规提及,因为它不会阻止废弃物过滤器释放出来第一类采用的缓存。这使它成为防止循环提及引起的缓存外泄的好工具。这是两个例子:
let object1 = {};let object2 = {};// create a WeakMaplet weakMap = new WeakMap();// create a circular reference by adding object1 to the WeakMap// and then adding the WeakMap to object1weakMap.set(object1, “some data”);object1.weakMap = weakMap;// create a WeakSet and add object2 to itlet weakSet = new WeakSet();weakSet.add(object2);// in this case, the garbage collector will be able to free up the memory// used by object1 and object2, since the references to them are weak
在这个例子中,我们建立了两个第一类,object1 和 object2,并透过将它分别添加到 WeakMap 和 WeakSet 来建立它之间的循环提及。
因为对这些第一类的提及很弱,废弃物过滤器将能够释放出来它采用的缓存,即使它仍在被提及。这有助于防止循环提及引起的缓存外泄。
2.采用废弃物过滤器 API
另一种缓存管理工作控制技术是采用废弃物过滤器 API,它允许
这对于调试缓存外泄和操控性问题很有用。
以下是两个例子:
let object1 = {};let object2 = {};// create a circular reference between object1 and object2object1.next = object2;object2.prev = object1;// manually trigger garbage collectiongc();
在此示例中,我们建立了两个第一类,object1 和 object2,并透过向它添加 next 和 prev 属性在它之间建立循环提及。然后,我们采用 gc() 表达式手动触发废弃物收集,这将释放出来第一类采用的缓存,即使它仍在被提及。
请务必注意,并非大部份 JavaScript 发动机都支持 gc() 表达式,其行为也可能因发动机而异。还须要注意的是,手动触发废弃物回收会对操控性产生影响,因此,建议谨慎采用,仅在必要时采用。
除了 gc() 表达式,JavaScript 还为一些 JavaScript 发动机提供了 global.gc() 和 global.gc() 表达式,也为一些应用程序发动机提供了 performance.gc() ,能用来检查 堆的当前状态并测量废弃物收集过程的操控性。
3.采用堆快照和分析器
JavaScript 还提供堆快照和分析器,可以帮助您介绍您的插件怎样采用缓存。堆快照允许您拍摄堆当前状态的快照并对其展开分析以查看什么样第一类采用的缓存最多。
下面是两个示例,说明怎样采用堆快照来辨识插件中的缓存外泄:
// Start a heap snapshotlet snapshot1 = performance.heapSnapshot();// Do some actions that might cause memory leaksfor (let i = 0; i < 100000; i++) { myArray.push({ largeData: new Array(1000000).fill(“some data”), id: i });}// Take another heap snapshotlet snapshot2 = performance.heapSnapshot();// Compare the two snapshots to see which objects were createdlet diff = snapshot2.compare(snapshot1);// Analyze the diff to see which objects are using the most memorydiff.forEach(function(item) { if (item.size > 1000000) { console.log(item.name); }});
在此示例中,我们在执行将大统计数据推送到字符串的循环之前和之后拍摄两个堆快照,然后,比较这两个快照以辨识在循环期间建立的第一类。
接着,我们能分析差异以查看什么样第一类采用了最多的缓存,这能帮助我们辨识由大统计数据引起的缓存外泄。
分析器允许您追踪插件的操控性并辨识缓存采用率高的区域:
let profiler = new Profiler();profiler.start();// do some actions that might cause memory leaksfor (let i = 0; i < 100000; i++) { myArray.push({ largeData: new Array(1000000).fill(“some data”), id: i });}profiler.stop();let report = profiler.report();// analyze the report to identify areas where memory usage is highfor (let func of report) { if (func.memory > 1000000) { console.log(func.name); }}
在这个例子中,我们采用 JavaScript 分析器来开始和停止追踪我们插件的操控性。该报告将显示有关已初始化表达式的信息以及每个表达式的缓存采用情况。
并非大部份 JavaScript 发动机和应用程序都支持堆快照和分析器,因此在您的插件中采用它之前检查兼容性很重要。
结论
我们已经介绍了 JavaScript 缓存管理工作的基础科学知识,包括废弃物回收过程、不同类型的缓存以及 JavaScript 中可用的缓存管理工作工具和控制技术。我们还讨论了缓存外泄的常用其原因,并提供了如何防止它的示例。透过花时间介绍和实施这些缓存管理工作最佳实践,您将能够建立消除缓存外泄可能性的插件。