2012-04-02 41 views
5

Tôi đã luôn luôn được giả định rằng các phím của một đối tượng được lưu trữ như là chuỗi, và rằng bất kỳ giá trị không phải chuỗi sẽ được đúc. Vì vậy, nó là dưới giả định này, trong khi viết một số mã mà phải lưu trữ một giá trị nhỏ cho nhiều ngàn phím, tôi chuyển đổi tất cả các phím để căn 36:Tên thuộc tính trên các đối tượng được lưu trữ trong Javascript như thế nào?

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

Sau đó, tôi quyết định xem liệu giả định của tôi thực sự chính xác và đã sử dụng trình hồ sơ của Chrome để kiểm tra mức sử dụng bộ nhớ. Gần đây là các bài kiểm tra tôi đã chạy và mức sử dụng bộ nhớ:

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 

Rõ ràng, các giả định của tôi đã bị tắt. Mặc dù vậy, điều tôi đang tự hỏi là cách chúng được lưu trữ và liệu hành vi này có phải là tiêu chuẩn hay chỉ là một số thủ thuật phụ đã được nhóm Chromium/WebKit thêm vào không?

Trả lời

0

Đó là tối ưu hóa trong Chromium. Tôi tin rằng nó có heuristics (here's one mention of it) để xác định cách hiệu quả nhất để lưu trữ các thuộc tính trong nội bộ. Tất cả những đặc tả của ECMAScript là giao diện giữa JavaScript và môi trường và không nói gì về cách các đối tượng tiếp xúc với JavaScript được thực hiện trong nội bộ.

3

Đây thực sự là một số thủ thuật phụ của V8.

Một JSObject (nội bộ C++ đại diện của một JS Object) có hai thuộc tính, elementsproperties, nơi mà các "yếu tố" là JS thuộc tính với chỉ số số, trong khi "tài sản" là JS thuộc tính với chỉ số chuỗi.

Rõ ràng, chỉ số bằng số tiêu thụ ít bộ nhớ hơn ở đây, vì tên thuộc tính không cần lưu trữ.

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

Một đối tượng JavaScript điển hình posesses hai mảng: một cho lưu trữ tên thuộc tính, một để lưu trữ các yếu tố số.

Điều này có thể được nhìn thấy từ mã nguồn 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); 
    } 
} 

tôi sẽ không đi vào chi tiết, nhưng lưu ý rằng SetObjectProperty cuộc gọi hoặc SetElement hoặc SetProperty, tùy thuộc vào khóa. Không chắc chắn tại sao kiểm tra không thành công trong trường hợp thử nghiệm của bạn key = i + '0'.

Các vấn đề liên quan