2012-04-02 14 views
5

Ben bir nesnenin tuşları dizeleri olarak saklandı varsayımı altında her zaman oldu ve olmayan herhangi bir dize değeri döküm olacağını. Yani, anahtarların binlerce için küçük değeri saklamak zorunda bazı kod yazarken, ben 36 dayandırmak tüm anahtarları dönüştürülür, bu varsayımı altında idi: SonraJavascript'te saklanan nesnelerdeki nitelik adları nasıl?

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

, benim varsayım olmadığını görmek için karar aslında doğruydu ve bellek kullanımını kontrol etmek için Chrome'un profiler kullandı.

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 

Açıkçası, benim varsayımlar kapalı idi: Kabaca burada koştum testleri ve bellek kullanımı vardır. Ama merak ediyorum ne bu davranış standarttır, ya da sadece bazı ekstra hile Krom/WebKit ekibi tarafından eklenmiş olan nasıl depolanıyor ve olup olmadığıdır? Chromium'da

cevap

0

It adlı optimizasyonlar. Özelliklerin dahili olarak depolanmasının en etkili yolunu belirlemek için sezgisel (here's one mention of it) olduğuna inanıyorum. ECMAScript spesifikasyonlarının dikte ettiği her şey, JavaScript ile ortam arasındaki arayüzdür ve JavaScript'e maruz kalan nesnelerin dahili olarak nasıl uygulandığı hakkında hiçbir şey söylemez.

3

Bu gerçekten V8 tarafından bazı ekstra hile olduğunu. "Özellikler" JS dize endeksleri niteliklerini ise

bir JSObject (a JS Object iç C++ temsili), "elemanlarının" JS sayısal indisli özellikleridir iki öznitelik, elements ve properties sahiptir. özellik adları saklı gerekli olmadığından

Açıkçası, sayısal endeksleri, burada çok daha az bellek tüketir. Sayısal elemanları depolamak için adlandırılmış özellikleri depolanması için bir başka:

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

Tipik JavaScript nesne iki diziyi posesses.

Bu

v8 kaynak kodundan görülebilir:

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); 
    } 
} 

detaylara girmeyeceğim ama ya bu SetObjectProperty çağrıları dikkate olmaz Tuşa bağlı olarak SetElement veya SetProperty. Yine de, neden test kutunuzda key = i + '0''un neden başarısız olduğunu bildiğinizden emin değilsiniz.