Memory overhead of typed arrays vs strings

前端 未结 2 698
南方客
南方客 2020-12-24 13:52

I am trying to reduce the memory usage of a javascript web application that stores a lot of information in memory in the form of a large number of small strings. When I chan

相关标签:
2条回答
  • 2020-12-24 14:33

    V8 developer here. Your conclusion makes sense: If you compare characters in a string to elements in a Uint8Array, the string will have less overhead. TypedArrays are great at providing fast access to typed elements; however having a large number of small TypedArrays is not memory efficient.

    The difference is in the object header size for strings and typed arrays.

    For a string, the object header is:

    1. hidden class pointer
    2. hash
    3. length
    4. payload

    where the payload is rounded up to pointer size alignment, so 16 bytes in this case.

    For a Uint8Array, you need the following:

    1. hidden class pointer
    2. properties pointer (unused)
    3. elements pointer (see below)
    4. array buffer pointer (see below)
    5. offset into array buffer
    6. byte length
    7. length of view into array buffer
    8. length (user-visible)
    9. embedder field #1
    10. embedder field #2

    11. array buffer: hidden class pointer

    12. array buffer: properties pointer (unused)
    13. array buffer: elements pointer (see below)
    14. array buffer: byte length
    15. array buffer: backing store
    16. array buffer: allocation base
    17. array buffer: allocation length
    18. array buffer: bit field (internal flags)
    19. array buffer: embedder field #1
    20. array buffer: embedder field #2

    21. elements object: hidden class pointer

    22. elements object: length (of the backing store)
    23. elements object: base pointer (of the backing store)
    24. elements object: offset to data start
    25. elements object: payload

    where, again, the payload is rounded up to pointer size alignment, so consumes 16 bytes here.

    In summary, each string consumes 5*8 = 40 bytes, each typed array consumes 26*8 = 208 bytes. That does seem like a lot of overhead; the reason is due to the various flexible options that TypedArrays provide (they can be overlapping views into ArrayBuffers, which can be allocated directly from JavaScript, or shared with WebGL and whatnot, etc).

    (It's not about "optimizing memory allocation" nor being "better at garbage collecting strings" -- since you're holding on to all the objects, GC does not play a role.)

    0 讨论(0)
  • 2020-12-24 14:34

    The typed arrays are not supposed to be used that way.

    If you want high memory efficiency, use just one typed array to hold all of your integer numbers. Instead of use a huge number of arrays to hold your integer numbers due to low level reasons.

    Those low level reasons are related to how much overhead is need to hold one object in memory, and that quantity depends on a few aspects like immutability and garbage collection. In this case hold one typed array has higher overhead than hold one simple string. Thats why you should pay that price one time only

    You should take advantage of:

    var a = [];                       for (let i=0; i<1000000; i++) a.push("1");
    var b = new Uint8Array(10000000); for (let i=0; i<1000000; i++) a[i] = 1;
    // 'b' is more memory efficient than 'a', just pay the price of Uint8Array one time
    // and save the wasted memory in string allocation overhead 
    
    0 讨论(0)
提交回复
热议问题