【发布时间】:2019-10-12 04:32:31
【问题描述】:
queryObjects 函数返回给定原型的实例。
我想检查这些实例的保留者。为此,我需要在 devtools 内存快照中找到它们。这些实例类型之一是“对象”,因此按类类型搜索没有帮助。他们太多了。
如何在快照中找到该特定实例?
【问题讨论】:
标签: javascript debugging memory-leaks google-chrome-devtools
queryObjects 函数返回给定原型的实例。
我想检查这些实例的保留者。为此,我需要在 devtools 内存快照中找到它们。这些实例类型之一是“对象”,因此按类类型搜索没有帮助。他们太多了。
如何在快照中找到该特定实例?
【问题讨论】:
标签: javascript debugging memory-leaks google-chrome-devtools
如果可以修改这些对象,您可以尝试以下技巧。
将从 queryObjects 获得的数组存储到一个临时变量中。您可以通过上下文菜单进行操作。然后运行以下代码给每个对象一个唯一的 id:
temp1.forEach((t, i) => t.__id = String(i))
然后拍摄堆快照。现在每个对象都应该可以通过 __id 字符串来识别。
【讨论】:
很难将queryObjects 返回的普通“对象”与堆快照中的所有普通对象区分开来
这是我为“标记”对象所做的工作,以便我可以轻松区分它们:
TaggedItem 类queryObjects
WeakMap 中
TaggedItem
WeakMap 垃圾收集
queryObjects 上应用装饰器
function queryObjects { /* Implementation */ }
// or process.env.NODE_ENV == 'development'
if (__DEV__) {
export default wrapWithObjectTagging(queryObjects);
}
else {
export default queryObjects;
}
装饰器实现
function wrapWithObjectTagging(func) {
function withObjectTagging(...args) {
const originalReturnValue = func.apply(this, args);
/* We're using Promise.resolve in case the original function returns a promise */
Promise.resolve(originalReturnValue)
.then((data) => {
// Weak map keys can be objects only
if (typeof data == 'object') {
const tag = new TaggedItem(data);
taggedItems.set(data, tag);
}
});
return originalReturnValue;
}
return withObjectTagging;
}
/**
* Capture tags in a weak map
* When the original object (key) is no longer used anywhere in app - the data (TaggedItem)
* is free for garbage collection and removed
* Using dev tools we see which TaggedItems are still retained and what's using them - preventing GC
* @type {WeakMap<object, TaggedItem>}
*/
const taggedItems = new WeakMap();
/**
* Class instances are easily tracked by Dev tools memory snapshots
* Wrapping a result with such instance allows us to track it without
* incurring extra weight
*/
class TaggedItem {
constructor(data) {
// This ref helps us inspect what is retaining the original data
this.ref = data;
/* This is not really necessary but makes the TaggedItem represent
Retained Memory more accurately */
Object.assign(this, data);
}
}
TaggedItem 直接引用原始数据,但由于没有引用 TaggedItem - 我们从不公开它 - 它不会阻止 WeakMap 垃圾收集原始数据和捕获的 TaggedItem它
以下是 Chrome 开发工具中的工作示例:
TaggedItem
report 属性保留更简单的方法是在原始对象上附加一个键
通过附加自定义字段进行装饰function wrapWithObjectTagging(func) {
function withObjectTagging(...args) {
const originalReturnValue = func.apply(this, args);
if (typeof originalReturnValue == 'object') {
originalReturnValue.__tag = new TaggedItem();
}
return originalReturnValue;
}
return withObjectTagging;
}
class TaggedItem {}
这样您仍然可以在开发工具中按TaggedItem 进行过滤,并查看保留了TaggedItem 和父对象的内容
第一种方法可以更好地估计总保留内存,而简单的方法只允许您跟踪保留原始内存的内容
【讨论】: