图片内存分析

167 阅读2分钟

打开 Chrome 的隐身模式,并关闭所有非必要的 Chrome 扩展,避免缓存和 Chrome 插件内存占用造成的影响

查看网页内存配额及消耗

window.performance.memory

使用 Performance 可视化检测内存泄漏

在 Chrome DevTools 的 Performance 面板勾选 Memory 并开启记录,之后在页面上执行一些操作。我们在记录数据的开始和结束时刻都手动进行一次 GC。

在结果图表中 HEAP 这一栏查看内存的使用情况,我们将一开始没有进行操作时的内存使用情况作为基准值,与最后停止操作并进行 GC 后的值进行比较,如果有较明显的差距,则说明产生了内存泄漏。

在Memory面板进一步分析内存泄露问题

使用内存堆快照检测分离的 DOM 内存泄漏

游离的DOM节点

一个 DOM 节点只有在没有被引用时才会被 GC,当 DOM 节点不在 DOM 树中,但是却被 JS 代码保留着引用,这种情况下会造成内存泄漏。

image.png

查看内存分配时间轴信息

在 Memory 面板选择 Allocation instrumentation on timeline 可以记录内存分配时间轴信息。Chrome 会周期性以一定的间隔记录内存堆快照,并在记录结束时进行最后一次快照,以此生成内存分配时间轴信息。如果较早时间分配的对象依然大量存活,则说明可能有内存泄漏的问题。

评估不同代码造成的内存消耗

图片存储对比

同时发送10张2M左右的高清图,发现在收到消息时,使用createObjectURL内存增长大概3k,使用base64内存增长大概2M

图片存储:Object URL vs base64

假设blob占用内存为n

存储形式blob是否被回收占用内存是否可跨会话使用
Object URLn
base641.33n

Object URL跨会话使用

  1. blob存储在IndexDB中,需要跨会话使用时,从IndexDB拿原始文件使用
// 假设 blob 是你获取到的 Blob 数据
const storeBlob = async (blob) => {
  const db = await openDB('my-database', 1, {
    upgrade(db) {
      db.createObjectStore('blobs');
    },
  });
  await db.put('blobs', blob, 'myBlobKey');
};

const getBlobFromDB = async () => {
  const db = await openDB('my-database', 1);
  return await db.get('blobs', 'myBlobKey');
};

const blobToBase64 = (blob) => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = () => {
      resolve(reader.result);
    };
    reader.onerror = reject;
    reader.readAsDataURL(blob);
  });
};

const convertStoredBlobToBase64 = async () => {
  const blob = await getBlobFromDB();
  if (blob) {
    const base64 = await blobToBase64(blob);
    console.log(base64);
    return base64;
  } else {
    console.log('No Blob found in storage');
  }
};

  1. 从Object URL提取blob ,转为base64
async function fetchBlobFromObjectURL(objectURL) {
  const response = await fetch(objectURL);
  const blob = await response.blob();
  return blob;
}
function blobToBase64(blob) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = () => {
      resolve(reader.result);
    };
    reader.onerror = reject;
    reader.readAsDataURL(blob);
  });
}
async function objectURLToBase64(objectURL) {
  try {
    const blob = await fetchBlobFromObjectURL(objectURL);
    const base64 = await blobToBase64(blob);
    return base64;
  } catch (error) {
    console.error('Error converting Object URL to Base64:', error);
    return null;
  }
}

// 使用示例
const objectURL = URL.createObjectURL(new Blob(['example content'], { type: 'text/plain' }));

objectURLToBase64(objectURL).then(base64 => {
  console.log(base64);
});