javascript - 如果对象的类型只是 "Object",如何在 DevTools 内存快照中找到特定对象?

标签 javascript debugging memory-leaks google-chrome-devtools

queryObjects 函数返回给定原型(prototype)的实例。 我想检查这些实例的保留器。为此,我需要在 devtools 内存快照中找到它们。这些实例类型之一是“对象”,因此按类类型搜索没有帮助。他们太多了。

如何在快照中找到特定实例?

最佳答案

很难将 queryObjects 返回的普通“对象”与堆快照中的所有普通对象区分开来

以下是我为“标记”对象所做的操作,以便我可以轻松区分它们:

  1. 创建一个可以在开发工具中轻松找到的 TaggedItem
  2. 创建一个包装函数来代替 queryObjects
  3. 包装函数将返回值保存在 WeakMap
  • key为原始返回值
  • 值为 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 开发者工具中的工作原理:

  1. 拍摄堆快照
  2. 搜索对象类名(TaggedItem)
  3. 选择一个项目
  4. 查看保留者
例子

Chrome Dev Tools Memory Usage Snapshot

  • 我们正在观察一个 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 以及父对象的内容

第一种方法可以更好地估计总保留内存,而简单的方法只允许您跟踪保留原始内存的内容

关于javascript - 如果对象的类型只是 "Object",如何在 DevTools 内存快照中找到特定对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56311832/

相关文章:

javascript - document.write javascript 函数不起作用

javascript - Firebase - Cloud Firestore 触发器幂等性

opencv - 在 Go 应用程序中查找内存泄漏

xcode - xcode7 调试器发生了什么变化,我无法再使用 "po"/Swift 查看变量

linux - malloc_stats和/proc/pid/stat的相关性

ios - 修复或避免默认第三方库中的内存泄漏

javascript - 位于 HTML 文件中的 Angular 变量中的特殊字符

javascript - Google Apps 脚本中的 "Shared Drive"支持

css - IE9 错误 - 它不应用样式(所有其他浏览器都适用)

debugging - OpenGL 抑制基于 MFC 对话框的应用程序中的异常