2

I'm creating a Chrome extension that stores a lot of data in chrome.storage.local. By "a lot," I mean that when I run something like this:

chrome.storage.local.getBytesInUse(i => console.log(i))

...I print 150873495, indicating that I'm storing about 150 MB. I would like to be able to store more than this. I'm aware that this is a lot of data for a Chrome extension, but it will be running on my own machine.

I previously posted How can I retrieve lots of data in chrome.storage.local?, and that issue was solved by a bug fix within Chrome. Now I have another problem.

I would like to transfer all of the data in chrome.storage.local to some sort of text file (such as JSON). However, when I run something as simple as this:

chrome.storage.local.get(
    null,
    result => {
      console.log("Records retrieved");
    }
);

...the memory usage of my extension (found in the Chrome task manager) spikes to about 2.4 GB, more than an order of magnitude greater than the 150 MB that the data takes up on the disk in chrome.storage.local. Let's say I then want to save this data to a file, using the method described in Chrome Extension: Local Storage, how to export. I need to call JSON.stringify:

chrome.storage.local.get(
    null,
    result => {
      console.log("Records retrieved");
      const json = JSON.stringify(result);
      console.log("JSON string length: " + json.length);
    }
);

It never gets to the "JSON string length" comment because the JSON.stringify call causes memory usage to go beyond the 4 GB memory limit, and the extension crashes. I have a couple of questions:

  • Is there a way to save this 150 MB of storage without using 4 GB of memory?
  • Is there an easy way to save this data in chunks? Given the asynchronous nature of JavaScript and chrome.storage, it seems like building a safe way to do this would be tricky.

Edit

As requested by @wOxxOm, here's some code used to generate fake data:

function randomString() {
  return Math.floor(Math.random() * 0xFFFFFFFF).toString(16);
}
for (let i = 0; i < 70000; i++) {
  const item = {time: Date.now()};
  for (let j = 0; j < 100; j++ ) {
    item[randomString()] = randomString();
  }
  const recordName = "record-" + Date.now() + "-" + randomString();
  const items = {};
  items[recordName] = item;
  chrome.storage.local.set(items);
}

This seems to take up about 160 MB in chrome.storage.local, but about 2.7 GB in memory.

Finn
  • 652
  • 7
  • 16
  • Could it be that 150MB is, in fact, the _compressed_ size, and the plain representation is really in the gigabytes? – Xan Nov 26 '18 at 13:50
  • @Xan that seems like a reasonable explanation. I'd be happy with generating a multi-GB file, if that's what the JSON representation ends up being. My problem is that I can't even do that right now. – Finn Nov 26 '18 at 13:54
  • How is your data organized within the storage? Can you add that to the question? – Xan Nov 26 '18 at 13:58
  • @wOxxOm puu.sh is firewall-blocked where I am for hosting malware, I'm afraid. – Xan Nov 26 '18 at 14:03
  • Mirror: https://drive.google.com/file/d/1p-dFqPVdu9BDUgoAQphqURhETgo1l6qo/view?usp=sharing – wOxxOm Nov 26 '18 at 14:06
  • @wOxxOm I added my data-generating code. I'm still getting high memory usage with my fake data, but I'm getting results similar to yours for your fake data. Perhaps it has something to do with how nested the data is? – Finn Nov 26 '18 at 15:30
  • 1
    Indeed, with non-uniform values I see that enormous spike in memory consumption. Until this is fixed in a future Chrome you'll probably have to find a standalone tool to read the files directly ("Local Extension Settings" in the browser profile dir) using some utility that can read LevelDB and export to JSON. Or write one yourself e.g. by using node.js modules. – wOxxOm Nov 26 '18 at 16:48
  • 1
    https://crbug.com/908487 – wOxxOm Nov 26 '18 at 18:06

0 Answers0