24

Mam kodu javascript, który wygląda tak:Jak zmusić JavaScript do głębokiego kopiowania ciągu znaków?

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

Później funkcja jest wywoływana z niektórych dużych ciągów (100 MB +). Chcę tylko zapisać krótki identyfikator, który znajduję w każdym ciągu. Jednak funkcja podłańcuchowa Google Chrome (w rzeczywistości regex w moim kodzie) zwraca tylko obiekt "plasterki", który odwołuje się do oryginału. Więc po serii wywołań do myFunc, na mojej zakładce chrome zabraknie pamięci, ponieważ tymczasowe obiekty huge_string nie mogą być zbędne.

Jak utworzyć kopię ciągu id, aby nie utracić odniesienia do huge_string, a huge_string może zostać zbuforowany?

enter image description here

+0

' "" + slice' nie wydaje się do pracy, ani nie' "" + plaster + "" '. Próbuję innych podejść. – AffluentOwl

+1

* "Funkcja podłańcuchowa (w rzeczywistości regex w moim kodzie) zwraca jedynie obiekt" plasterki ", który odwołuje się do oryginału" * - Huh? '.substr()', '.substring()', '.slice()', a wszystkie odpowiednie funkcje regex zwracają * nowy * ciąg znaków. Czy drugi kod wywołuje funkcję "myClass.myFunc()", zachowując odwołanie do Twojego ogromnego ciągu? Jeśli twój prawdziwy kod jest bardziej złożony, czy przypadkiem nie trzyma wielkich łańcuchów w zamknięciach? – nnnnnn

+2

@nnnnnn Nie można stwierdzić, czy jest to "nowy" ciąg znaków * dane * z JavaScript; implementacje * mogą * udostępniać podstawowe dane bez naruszania jakiejkolwiek części ECMAScript. Firefox ma pół tuzina [różnych implementacji ciągów] (https://blog.mozilla.org/ejpbruel/2012/02/06/how-strings-are-implemented-in-spidermonkey-2/) (zobacz w szczególności JSDependentString) i nie jestem zaskoczony, jeśli Chrome ma podobne optymalizacje (które mogą działać niepożądanie w niektórych skrajnych przypadkach). Biorąc to pod uwagę ... nie byłbym strasznie zaskoczony, gdyby to był czerwony śledź. – user2864740

Odpowiedz

29

realizacji JavaScript jest z ECMAScript może się wahać od przeglądarki do przeglądarki, jednak dla Chrome, wiele operacji String (substr, plaster, regex, etc.) po prostu zachować odniesień do oryginalnego napisu zamiast dokonywania kopie strunowy. Jest to znany problem w Chrome (Bug #2869). Aby wymusić kopię napisu, Następujący kod działa:

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

Ten kod działa przez dodanie miejsca do przodu łańcucha. Ta konkatenacja powoduje utworzenie ciągu znaków w implementacji Chrome. Następnie można odwoływać się do podciągu za spacją.

Problem z rozwiązaniem zostały odtworzone tutaj: http://jsfiddle.net/ouvv4kbs/1/

UWAGA: zajmuje dużo czasu, aby załadować, otwórz konsolę debugowania Chrome zobaczyć wydruk postępu.

// 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

+0

var string_copy = original_string.slice (0); –

+0

@WesleyStam Myślę, że powodem, dla którego działa post użytkownika AffluentOwl jest to, że przygotowuje znak do łańcucha, który powoduje, że łańcuch jest kopiowany, ponieważ operator plasterek nie kopiuje w rzeczywistości takiego łańcucha, jak powinien. – NightFantom

Powiązane problemy