a

Câu hỏi Làm thế nào để có được kích thước của một đối tượng JavaScript?


Tôi muốn biết kích thước bị chiếm bởi một đối tượng JavaScript.

Thực hiện chức năng sau:

function Marks(){
  this.maxMarks = 100;
}

function Student(){
  this.firstName = "firstName";
  this.lastName = "lastName";
  this.marks = new Marks();
}

Bây giờ tôi khởi tạo student:

var stud = new Student();

để tôi có thể làm những việc như

stud.firstName = "new Firstname";

alert(stud.firstName);

stud.marks.maxMarks = 200;

v.v.

Bây giờ, stud đối tượng sẽ chiếm một số kích thước trong bộ nhớ. Nó có một số dữ liệu và nhiều đối tượng hơn.

Làm cách nào để tìm ra dung lượng bộ nhớ stud đối tượng chiếm? Một cái gì đó giống như một sizeof() trong JavaScript? Nó sẽ thực sự tuyệt vời nếu tôi có thể tìm thấy nó trong một cuộc gọi chức năng như sizeof(stud).

Tôi đã tìm kiếm trên Internet trong nhiều tháng - không thể tìm thấy nó (được hỏi trong một vài diễn đàn — không có trả lời).


203
2017-08-08 07:58


gốc


Có (sẽ phát sinh) rất nhiều lý do tại sao tôi cần phải tìm kích thước của một đối tượng trong JavaScript. Tôi mới sử dụng JavaScript nên tôi không tuân theo các phương pháp hay nhất. Tôi vẫn đang học chúng. Tôi đã phát triển một phần mở rộng firefox mà tôi chắc chắn là sử dụng bộ nhớ nhiều hơn nó nên. Tôi đang làm việc trên một số cách để (hy vọng) giảm sử dụng bộ nhớ .. im nói về hàng ngàn trường hợp nhiều đối tượng trên mỗi tab, do đó, bộ nhớ không quan trọng! Vấn đề là, tôi muốn biết nếu những nỗ lực giảm trí nhớ của tôi thực sự giúp giảm bộ nhớ ... và bao nhiêu.
Nếu bạn đã xây dựng một phần mở rộng FF tôi khuyên bạn nên điều tra ở một mức độ ngôn ngữ cao hơn so với JS - xem những gì tác động trên FF chính nó là. - annakata
Ngôn ngữ cấp cao hơn JS? đó sẽ là gì trong trường hợp này?
Nó không phải là kích thước mà vấn đề anyway. Đó là cách bạn sử dụng nó. PS: Điều gì một stud! - Thomas Eding
@SpencerRuport Số một lý do để biết kích thước đối tượng sẽ là cho các ứng dụng có khả năng ngoại tuyến html5, nơi bạn có đôi khi không gian lưu trữ giới hạn (5-10Mb có thể được ăn nhanh cho một ứng dụng chuyên sâu dữ liệu). - David


Các câu trả lời:


Tôi đã tính lại mã trong câu trả lời gốc. Tôi đã loại bỏ đệ quy và loại bỏ các chi phí tồn tại giả định.

function roughSizeOfObject( object ) {

    var objectList = [];
    var stack = [ object ];
    var bytes = 0;

    while ( stack.length ) {
        var value = stack.pop();

        if ( typeof value === 'boolean' ) {
            bytes += 4;
        }
        else if ( typeof value === 'string' ) {
            bytes += value.length * 2;
        }
        else if ( typeof value === 'number' ) {
            bytes += 8;
        }
        else if
        (
            typeof value === 'object'
            && objectList.indexOf( value ) === -1
        )
        {
            objectList.push( value );

            for( var i in value ) {
                stack.push( value[ i ] );
            }
        }
    }
    return bytes;
}

137
2017-08-10 10:55



bạn cũng có thể nghĩ về các khóa đối tượng - zupa
Bất cứ ai đã hạ cánh ở đây tìm kiếm loại nhỏ nhất cho các mục đích sai / đúng, nó có vẻ là không xác định / null. - zupa
Vâng. Các ký tự trong JavaScript được lưu trữ theo ECMA-262 3rd Edition Specification - bclary.com/2004/11/07/#a-4.3.16 - thomas-peter
Hàm này không tính các tham chiếu bị ẩn trong các bao đóng. Ví dụ var a={n:1}; var b={a:function(){return a}}; roughSizeOfObject(b) - đây b giữ tham chiếu đến a, nhưng roughSizeOfObject() trả về 0. - Roman Pominov
Cảm ơn Roman vì đã chỉ ra điều này. Tuy nhiên, tôi không nghĩ rằng nó sẽ rất có ý nghĩa để bao gồm kết quả của các hàm nhưng nó có thể hữu ích bằng cách nào đó tính toán kích thước của hàm. Tôi sẽ xem xét nó. Tôi cũng đã cân nhắc việc thêm một tùy chọn sẽ bao gồm kích thước của tên 'khóa'. - thomas-peter


Google Chrome Heap Profiler cho phép bạn kiểm tra việc sử dụng bộ nhớ đối tượng.

Bạn cần có khả năng xác định vị trí đối tượng trong dấu vết có thể phức tạp. Nếu bạn ghim đối tượng vào Window toàn cục, nó sẽ khá dễ tìm từ chế độ liệt kê "Chứa".

Trong ảnh chụp màn hình đính kèm, tôi đã tạo một đối tượng có tên là "testObj" trên cửa sổ. Tôi sau đó nằm trong profiler (sau khi thực hiện một ghi âm) và nó cho thấy kích thước đầy đủ của đối tượng và tất cả mọi thứ trong nó dưới "kích thước giữ lại".

Thêm chi tiết về bộ nhớ phân tích.

Chrome profiler

Trong ảnh chụp màn hình ở trên, đối tượng hiển thị kích thước được giữ lại là 60. Tôi tin rằng đơn vị là byte ở đây.


80
2017-09-13 14:28



Câu trả lời này đã giải quyết được vấn đề của tôi cùng với: developers.google.com/chrome-developer-tools/docs/… . Mẹo nhanh: chụp nhanh Heap Snapshot, chạy tác vụ bạn nghi ngờ bị rò rỉ, chụp nhanh Heap Snapshot mới và chọn comparison xem ở dưới cùng. Nó làm cho rõ ràng những gì các đối tượng đã được tạo ra giữa hai ảnh chụp nhanh. - Johnride
Đây có lẽ là giải pháp sạch nhất. - Luca Steeb
Những lời cảm ơn tốt đẹp. - Leng
So sánh, được đề cập bởi @Johnride, hiện là một trình đơn kéo xuống ở trên cùng. - frandroid
Shallow size có vẻ như 40 cho cả hai { a:"55c2067aee27593c03b7acbe", b:"55c2067aee27593c03b7acbe", c:null, d:undefined } và { c:null, d:undefined } các đối tượng. Là nó ổn? - efkan


Tôi chỉ viết điều này để giải quyết một vấn đề tương tự (ish). Nó không chính xác làm những gì bạn có thể đang tìm kiếm, tức là nó không tính đến cách trình thông dịch lưu trữ đối tượng.

Nhưng, nếu bạn đang sử dụng V8, nó sẽ cung cấp cho bạn một xấp xỉ khá ok như các prototyping tuyệt vời và các lớp ẩn lick lên hầu hết các chi phí.

function roughSizeOfObject( object ) {

    var objectList = [];

    var recurse = function( value )
    {
        var bytes = 0;

        if ( typeof value === 'boolean' ) {
            bytes = 4;
        }
        else if ( typeof value === 'string' ) {
            bytes = value.length * 2;
        }
        else if ( typeof value === 'number' ) {
            bytes = 8;
        }
        else if
        (
            typeof value === 'object'
            && objectList.indexOf( value ) === -1
        )
        {
            objectList[ objectList.length ] = value;

            for( i in value ) {
                bytes+= 8; // an assumed existence overhead
                bytes+= recurse( value[i] )
            }
        }

        return bytes;
    }

    return recurse( object );
}

64
2018-06-14 23:30



@Liangliang Zheng - tuyệt vời điểm lại vòng lặp vô hạn, cảm ơn. Hy vọng bạn không phiền nếu tôi tái biểu diễn nó một chút và cập nhật của tôi sau khi làm việc (?) - thomas-peter
Tôi sẽ thử băng ghế dự bị này tối nay với node.js và nhận được một số hệ số tốt hơn tại chỗ. - thomas-peter
Dòng 'bytes + = recurse (value [i])', ném một lỗi trong FF 14.01 của tôi: NS_ERROR_FAILURE: Mã lỗi trả về thành phần: 0x80004005 (NS_ERROR_FAILURE) [nsIDOMHTMLInputElement.selectionStart]. Trên một trong những Object của tôi, nếu tôi thử một cái khác, nó không, có thể là một lỗi trình duyệt, hoặc mã không hoạt động cho mọi đối tượng (cái không hoạt động có chứa các hàm, cái mà không hoạt động) t) - TrySpace
@TrySpace OK cảm ơn vì điều đó. Tôi đã tái xác nhận chức năng này dưới đây để không sử dụng đệ quy. Tôi hy vọng nó hoạt động tốt hơn cho bạn. - thomas-peter
Đó là PHP (gulp) mà tôi phải tìm kiếm - Tôi đã ngừng yêu cô ấy từ lâu rồi nhưng cô ấy trả tiền hóa đơn. Dù sao, cảm ơn Tom, phản hồi giống như là cách tốt hơn so với điểm danh tiếng. - thomas-peter


Đôi khi tôi sử dụng điều này để gắn cờ các đối tượng thực sự lớn có thể đi tới máy khách từ máy chủ. Nó không đại diện cho dấu chân bộ nhớ. Nó chỉ giúp bạn tiết kiệm chi phí để gửi hoặc lưu trữ.

Cũng lưu ý, nó là chậm, dev chỉ. Nhưng đối với việc nhận được một câu trả lời ballpark với một dòng mã nó rất hữu ích cho tôi.

roughObjSize = JSON.stringify(bigObject).length;

39
2018-01-28 05:42



Từ các thử nghiệm của tôi, phương thức này nhanh hơn đáng kể so với trường hợp của đối tượng sizeof vì nó không có lệnh gọi _.isObject () chậm từ lodash. Ngoài ra các kích thước trả lại là khá so sánh với các ước tính sơ bộ. Ý chính gist.github.com/owenallenaz/ff77fc98081708146495 . - Nucleon
Quá tệ nó vỡ ra khi vật thể quá lớn. :( - cregox
Không thể sử dụng với cấu trúc hình tròn VM1409:1 Uncaught TypeError: Converting circular structure to JSON :( vẫn hữu ích - givanse


Đây là một Mô-đun NPM để nhận kích thước đối tượng, bạn có thể cài đặt nó với npm install object-sizeof

  var sizeof = require('object-sizeof');

  // 2B per character, 6 chars total => 12B
  console.log(sizeof({abc: 'def'}));

  // 8B for Number => 8B
  console.log(sizeof(12345));

  var param = { 
    'a': 1, 
    'b': 2, 
    'c': {
      'd': 4
    }
  };
  // 4 one two-bytes char strings and 3 eighth-bytes numbers => 32B
  console.log(sizeof(param));

30
2018-05-18 11:46



sizeof (new Date ()) === 0 và sizeof ({}) === 0. Đó có phải là mục đích? - Philipp Claßen


Một chút muộn cho bữa tiệc, nhưng đây là một giải pháp nhỏ gọn hơn cho vấn đề này:

const typeSizes = {
  "undefined": () => 0,
  "boolean": () => 4,
  "number": () => 8,
  "string": item => 2 * item.length,
  "object": item => !item ? 0 : Object
    .keys(item)
    .reduce((total, key) => sizeOf(key) + sizeOf(item[key]) + total, 0)
};

const sizeOf = value => typeSizes[typeof value](value);

18
2018-04-01 09:32



Vì vậy, đây là kích thước trong KB? hoặc bit? - vincent thorpe
@ vincent-thorpe Nó tính bằng byte. - Dan
Kịch bản đẹp, cần sửa đổi cho các tham chiếu tuần hoàn. - Jim Pedid
Tôi vừa thử nghiệm thuật toán của bạn trên một mảng dữ liệu khổng lồ trong một quy trình nút, nó báo cáo 13GB, nhưng nút tiêu thụ 22GB, bất kỳ ý tưởng nào về sự khác biệt đến từ đâu? Không có gì hơn trong bộ nhớ. - Josu Goñi


Đây là một phương pháp hacky, nhưng tôi đã thử nó hai lần với các con số khác nhau và nó có vẻ là nhất quán.

Những gì bạn có thể làm là cố gắng và phân bổ khổng lồ số lượng đối tượng, như một hoặc hai triệu đối tượng thuộc loại bạn muốn. Đặt các đối tượng trong một mảng để ngăn chặn bộ thu gom rác phát hành chúng (lưu ý rằng điều này sẽ thêm một phần bộ nhớ nhỏ vì mảng, nhưng tôi hy vọng điều này không thành vấn đề và bên cạnh đó nếu bạn lo lắng về các đối tượng đang ở trong bộ nhớ , bạn lưu trữ chúng ở đâu đó). Thêm một cảnh báo trước và sau khi phân bổ và trong mỗi cảnh báo, hãy kiểm tra dung lượng bộ nhớ mà Firefox đang thực hiện. Trước khi bạn mở trang thử nghiệm, hãy đảm bảo bạn có một phiên bản Firefox mới. Mở trang, lưu ý việc sử dụng bộ nhớ sau khi cảnh báo "trước" được hiển thị. Đóng cảnh báo, đợi bộ nhớ được cấp phát. Trừ bộ nhớ mới ra khỏi bộ nhớ cũ và chia bộ nhớ đó cho số lượng phân bổ. Thí dụ:

function Marks()
{
  this.maxMarks = 100;
}

function Student()
{
  this.firstName = "firstName";
  this.lastName = "lastName";
  this.marks = new Marks();
}

var manyObjects = new Array();
alert('before');
for (var i=0; i<2000000; i++)
    manyObjects[i] = new Student();
alert('after');

Tôi đã thử điều này trong máy tính của tôi và quá trình này có 48352K bộ nhớ khi cảnh báo "trước" được hiển thị. Sau khi phân bổ, Firefox có 440236K bộ nhớ. Đối với phân bổ 2 triệu, đây là khoảng 200 byte cho mỗi đối tượng.

Tôi đã thử nó một lần nữa với phân bổ 1 triệu và kết quả là tương tự: 196 byte cho mỗi đối tượng (tôi cho rằng dữ liệu phụ trong 2mill đã được sử dụng cho mảng).

Vì vậy, đây là một phương pháp hacky có thể giúp bạn. JavaScript không cung cấp phương thức "sizeof" vì lý do: mỗi triển khai JavaScript khác nhau. Ví dụ: trong Google Chrome, cùng một trang sử dụng khoảng 66 byte cho mỗi đối tượng (đánh giá từ trình quản lý tác vụ ít nhất).


16
2017-08-08 09:57



Hey .. cảm ơn về kỹ thuật này. Tôi đã có đó là kế hoạch B không có cách trực tiếp nào để đo lường mức sử dụng bộ nhớ.
Mỗi C ​​và C ++ thực hiện cũng khác nhau. ;) Kích thước của một kiểu dữ liệu trong C hoặc C ++ là thực hiện cụ thể. Tôi thấy không có lý do JavaScript không thể hỗ trợ một toán tử như vậy, mặc dù nó sẽ không phục vụ cùng một mục đích hoặc có ý nghĩa giống như trong C hoặc C ++ (đó là các ngôn ngữ cấp thấp hơn và đo kích thước thực của một cố định- loại dữ liệu kích thước tại thời gian biên dịch trái ngược với kích thước biến của đối tượng JavaScript động tại thời gian chạy). - bambams


Xin lỗi tôi không thể bình luận, vì vậy tôi chỉ tiếp tục công việc từ tomwrong. Phiên bản nâng cao này sẽ không tính đối tượng nhiều hơn một lần, do đó không có vòng lặp vô hạn. Thêm vào đó, tôi nghĩ rằng chìa khóa của một đối tượng cũng nên được tính, gần.

function roughSizeOfObject( value, level ) {
    if(level == undefined) level = 0;
    var bytes = 0;

    if ( typeof value === 'boolean' ) {
        bytes = 4;
    }
    else if ( typeof value === 'string' ) {
        bytes = value.length * 2;
    }
    else if ( typeof value === 'number' ) {
        bytes = 8;
    }
    else if ( typeof value === 'object' ) {
        if(value['__visited__']) return 0;
        value['__visited__'] = 1;
        for( i in value ) {
            bytes += i.length * 2;
            bytes+= 8; // an assumed existence overhead
            bytes+= roughSizeOfObject( value[i], 1 )
        }
    }

    if(level == 0){
        clear__visited__(value);
    }
    return bytes;
}

function clear__visited__(value){
    if(typeof value == 'object'){
        delete value['__visited__'];
        for(var i in value){
            clear__visited__(value[i]);
        }
    }
}

roughSizeOfObject(a);

10
2018-06-16 06:03



Tôi nghĩ rằng điều này là chính xác hơn vì nó đếm các phím, mặc dù nó đếm số '__visited__' - Sam Hasler
Kiểm tra typeof value === 'object'là không đủ và bạn sẽ có ngoại lệ nếu giá trị là null. - floribon
Điều này đã được blazing nhanh cho đối tượng của tôi (mà tôi khá tự tin có cách hơn 5mb), so với bất kỳ câu trả lời của @ tomwrong. Nó cũng chính xác hơn (như nó nói 3mb hoặc hơn) nhưng vẫn còn cách quá xa thực tế. Bất kỳ manh mối nào về những gì nó có thể không được tính? - cregox


tôi muốn biết nếu những nỗ lực giảm trí nhớ của tôi thực sự giúp giảm bộ nhớ

Theo dõi nhận xét này, đây là những gì bạn nên làm: Cố gắng tạo ra một vấn đề về bộ nhớ - Viết mã để tạo tất cả các đối tượng này và tăng giới hạn trên cho đến khi bạn gặp phải vấn đề (Lỗi trình duyệt, Đóng trình duyệt hoặc lỗi Out-Of-memory). Lý tưởng nhất là bạn nên lặp lại thử nghiệm này với các trình duyệt khác nhau và hệ điều hành khác nhau.

Bây giờ có hai lựa chọn: tùy chọn 1 - Bạn đã không thành công trong sản xuất vấn đề bộ nhớ. Do đó, bạn đang lo lắng cho không có gì. Bạn không có vấn đề về bộ nhớ và chương trình của bạn vẫn ổn.

tùy chọn 2 - bạn đã nhận được một vấn đề bộ nhớ. Bây giờ hãy tự hỏi liệu giới hạn mà tại đó vấn đề xảy ra là hợp lý (nói cách khác: có khả năng là số lượng đối tượng này sẽ được tạo ra khi sử dụng mã của bạn bình thường). Nếu câu trả lời là 'Không' thì bạn ổn. Nếu không, bây giờ bạn biết có bao nhiêu đối tượng mà mã của bạn có thể tạo. Làm lại thuật toán sao cho nó không vi phạm giới hạn này.


5
2017-08-08 09:34



Từ một điểm bộ nhớ, phần mở rộng của tôi thêm một số đối tượng cho mỗi trang / tab được mở trong Firefox. "Số" tỷ lệ thuận với kích thước của trang. Giả sử rằng người dùng "quyền lực" có bất cứ nơi nào giữa 15 - 20 tab mở, và nếu trang web có nhiều nội dung, trình duyệt sẽ trở nên chậm và bực bội không đáp ứng sau một thời gian. Điều này xảy ra ngay cả khi tôi không cố gắng nhấn mạnh ứng dụng. Tôi có kế hoạch viết lại mã mà tôi nghĩ rằng sẽ giảm rất nhiều việc tạo đối tượng. Tôi chỉ muốn chắc chắn rằng không. của các đối tượng giảm đến một cái gì đó để nó là giá trị nó
@Senthil: nhưng kích thước đối tượng không có ý nghĩa trừ khi bạn biết số lượng bộ nhớ có sẵn. Vì số lượng bộ nhớ có khả năng vẫn là một bí ẩn, nói về mặt #objects cũng hữu ích như nói về thuật ngữ #bytes - Itay Maman