2012-04-02 14 views
5

Sono sempre stato supposto che le chiavi di un oggetto fossero memorizzate come stringhe e che qualsiasi valore non stringa venisse eseguito. Quindi, era sotto questa ipotesi, durante la scrittura del codice che ha dovuto memorizzare un valore piccolo per molte migliaia di chiavi, ho convertito tutte le chiavi di basare 36:Come sono i nomi degli attributi sugli oggetti memorizzati in Javascript?

// theKey is an integer 
myMap[theKey.toString(36)] = theValue; 

Poi, ho deciso di vedere se la mia ipotesi era effettivamente corretto e ha utilizzato il profiler di Chrome per verificare l'utilizzo della memoria. Circa ecco le prove mi sono imbattuto e l'utilizzo della memoria:

window.objIntegers = {}; 
for (i = 100000; i--) window.objIntegers[i] = 'a'; 
// 786kb 

window.objStrings = {}; 
for (i = 100000; i--) window.objStrings[i.toString(36)] = 'a'; 
// 16.7mb! 

// and the same pattern but with: 
key = i + .5; // 16.7mb 
key = i + ''; // 786kb 
key = '0' + i; // 16.7mb 
key = i + '0'; // 16.7mb 

Ovviamente, la mia ipotesi erano fuori. Quello che mi sto chiedendo, è come vengono memorizzati e se questo comportamento è standard o solo qualche trucco extra aggiunto dal team di Chromium/WebKit?

risposta

0

ottimizzazioni è tutto in cromo. Credo che abbia l'euristica (here's one mention of it) per determinare il modo più efficiente di memorizzare le proprietà internamente. Tutto ciò che detta la specifica ECMAScript è l'interfaccia tra JavaScript e l'ambiente e non dice nulla su come gli oggetti esposti a JavaScript siano implementati internamente.

3

Questo è davvero un po 'di inganno extra V8.

A JSObject (rappresentazione interna C++ di un JS Object) ha due attributi, elements e properties, dove gli "elementi" sono attributi JS con indici numerici, mentre le "proprietà" sono attributi JS con indici di stringa.

Ovviamente, indici numerici consumano molta meno memoria qui, poiché i nomi di proprietà non devono essere memorizzati.

http://code.google.com/intl/de-DE/chrome/devtools/docs/memory-analysis-101.html#primitive_objects

Un tipico oggetto JavaScript possiedees due matrici: una per la memorizzazione proprietà denominate, un altro per memorizzare elementi numerici.

questo può essere visto dal codice sorgente v8:

http://code.google.com/p/v8/source/browse/trunk/src/objects.h#1483

// [properties]: Backing storage for properties. 
... 
// [elements]: The elements (properties with names that are integers). 

http://code.google.com/p/v8/source/browse/trunk/src/runtime.cc#4462

MaybeObject* Runtime::SetObjectProperty(Isolate* isolate, 
             Handle<Object> object, 
             Handle<Object> key, 
             Handle<Object> value, 
             PropertyAttributes attr, 
             StrictModeFlag strict_mode) { 
    ... 

    // Check if the given key is an array index. 
    uint32_t index; 
    if (key->ToArrayIndex(&index)) { 
    // In Firefox/SpiderMonkey, Safari and Opera you can access the characters 
    // of a string using [] notation. We need to support this too in 
    // JavaScript. 
    // In the case of a String object we just need to redirect the assignment to 
    // the underlying string if the index is in range. Since the underlying 
    // string does nothing with the assignment then we can ignore such 
    // assignments. 
    if (js_object->IsStringObjectWithCharacterAt(index)) { 
     return *value; 
    } 

    Handle<Object> result = JSObject::SetElement(
     js_object, index, value, attr, strict_mode, set_mode); 
    if (result.is_null()) return Failure::Exception(); 
    return *value; 
    } 

    if (key->IsString()) { 
    Handle<Object> result; 
    if (Handle<String>::cast(key)->AsArrayIndex(&index)) { 
     result = JSObject::SetElement(
      js_object, index, value, attr, strict_mode, set_mode); 
    } else { 
     Handle<String> key_string = Handle<String>::cast(key); 
     key_string->TryFlatten(); 
     result = JSReceiver::SetProperty(
      js_object, key_string, value, attr, strict_mode); 
    } 
    if (result.is_null()) return Failure::Exception(); 
    return *value; 
    } 

    // Call-back into JavaScript to convert the key to a string. 
    bool has_pending_exception = false; 
    Handle<Object> converted = Execution::ToString(key, &has_pending_exception); 
    if (has_pending_exception) return Failure::Exception(); 
    Handle<String> name = Handle<String>::cast(converted); 

    if (name->AsArrayIndex(&index)) { 
    return js_object->SetElement(
     index, *value, attr, strict_mode, true, set_mode); 
    } else { 
    return js_object->SetProperty(*name, *value, attr, strict_mode); 
    } 
} 

Non voglio entrare nei dettagli, ma si noti che SetObjectProperty chiamate sia SetElement o SetProperty, a seconda della chiave. Non sei sicuro del motivo per cui il controllo fallisce nel tuo caso di test key = i + '0'.

Problemi correlati