it-swarm.com.de

Wie erzwinge ich, dass JavaScript einen String tief kopiert?

Ich habe einen Javascript-Code, der so aussieht:

var myClass = {
  ids: {}
  myFunc: function(huge_string) {
     var id = huge_string.substr(0,2);
     ids[id] = true;
  }
}

Später wird die Funktion mit einigen großen Strings (100 MB +) aufgerufen. Ich möchte nur eine kurze ID speichern, die ich in jeder Zeichenfolge finde. Die Unterzeichenfolge-Funktion von Google Chrome (eigentlich ein regulärer Ausdruck in meinem Code) gibt jedoch nur ein "Sliced ​​String" -Objekt zurück, das auf das Original verweist. Nach einer Reihe von Aufrufen von myFunc hat mein Chrome-Register keinen Speicher mehr, da die temporären huge_string-Objekte nicht in der Lage sind, Müll zu sammeln.

Wie kann ich eine Kopie der Zeichenfolge id erstellen, damit ein Verweis auf huge_string nicht beibehalten wird und der huge_string Müll gesammelt werden kann?

 enter image description here

36
AffluentOwl

Die Implementierung von ECMAScript durch JavaScript kann von Browser zu Browser variieren. Bei Chrome behalten viele String-Vorgänge (substr, slice, regex usw.) jedoch nur Verweise auf den ursprünglichen String bei, anstatt Kopien des Strings zu erstellen. Dies ist ein bekanntes Problem in Chrome ( Fehler # 2869 ). Um eine Kopie der Zeichenfolge zu erzwingen, funktioniert der folgende Code:

var string_copy = (' ' + original_string).slice(1);

Dieser Code fügt ein Leerzeichen vor die Zeichenfolge ein. Diese Verkettung führt zu einer String-Kopie in der Chrome-Implementierung. Dann kann die Teilzeichenfolge nach dem Leerzeichen referenziert werden.

Dieses Problem mit der Lösung wurde hier neu erstellt: http://jsfiddle.net/ouvv4kbs/1/

WARNUNG: Das Laden dauert lange. Öffnen Sie die Chrome-Debug-Konsole, um einen Fortschrittsausdruck anzuzeigen.

// We would expect this program to use ~1 MB of memory, however taking
// a Heap Snapshot will show that this program uses ~100 MB of memory.
// If the processed data size is increased to ~1 GB, the Chrome tab
// will crash due to running out of memory.

function randomString(length) {
  var alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  var result = '';
  for (var i = 0; i < length; i++) {
    result +=
        alphabet[Math.round(Math.random() * (alphabet.length - 1))];
  }
  return result;
};

var substrings = [];
var extractSubstring = function(huge_string) {
  var substring = huge_string.substr(0, 100 * 1000 /* 100 KB */);
  // Uncommenting this line will force a copy of the string and allow
  // the unused memory to be garbage collected
  // substring = (' ' + substring).slice(1);
  substrings.Push(substring);
};

// Process 100 MB of data, but only keep 1 MB.
for (var i =  0; i < 10; i++) {
  console.log(10 * (i + 1) + 'MB processed');
  var huge_string = randomString(10 * 1000 * 1000 /* 10 MB */);
  extractSubstring(huge_string);
}

// Do something which will keep a reference to substrings around and
// prevent it from being garbage collected.
setInterval(function() {
  var i = Math.round(Math.random() * (substrings.length - 1));
  document.body.innerHTML = substrings[i].substr(0, 10);
}, 2000);

 enter image description here

38
AffluentOwl

Ich verwende die Object.assign () - Methode für Zeichenfolge, Objekt, Array usw.:

const newStr = Object.assign("", myStr);
const newObj = Object.assign({}, myObj);
const newArr = Object.assign([], myArr);

Beachten Sie, dass Object.assign nur die Schlüssel und ihre Eigenschaftswerte innerhalb eines Objekts kopiert (nur auf einer Ebene). Informationen zum tiefen Klonen eines verschachtelten Objekts finden Sie im folgenden Beispiel:

let obj100 = { a:0, b:{ c:0 } };
let obj200 = JSON.parse(JSON.stringify(obj100));
obj100.a = 99; obj100.b.c = 99; // No effect on obj200
4
Daniel C. Deng

Ich bekam ein Problem, als ich in ein Array schob. Jeder Eintrag würde als die gleiche Zeichenfolge enden, da er auf einen Wert in einem Objekt verweist, der sich geändert hat, als ich die Ergebnisse über eine .next () - Funktion durchlaufen habe. Das erlaubte mir, die Zeichenfolge zu kopieren und eindeutige Werte in meinen Array-Ergebnissen zu erhalten:

while (results.next()) {
  var locationName = String(results.name);
  myArray.Push(locationName);
}
0
Kyle s

Sie können verwenden:

 String.prototype.repeat(1) 

Es scheint gut zu funktionieren. Lesen Sie die MDN-Dokumentation zu repeat .

0
nuttybrewer