จะรับขนาดของวัตถุ JavaScript ได้อย่างไร


296

ฉันต้องการทราบขนาดที่ครอบครองโดยวัตถุ JavaScript

ใช้ฟังก์ชั่นต่อไปนี้:

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

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

ตอนนี้ฉันยกตัวอย่างstudent:

var stud = new Student();

เพื่อให้ฉันสามารถทำสิ่งที่ชอบ

stud.firstName = "new Firstname";

alert(stud.firstName);

stud.marks.maxMarks = 200;

เป็นต้น

ตอนนี้studวัตถุจะครอบครองขนาดในหน่วยความจำ มันมีข้อมูลและวัตถุมากกว่านี้

ฉันจะรู้ได้อย่างไรว่าหน่วยความจำstudนั้นมีวัตถุอยู่มากแค่ไหน? สิ่งที่ชอบsizeof()ใน JavaScript? sizeof(stud)มันจะน่ากลัวจริงๆว่าฉันจะพบว่ามันออกมาในการเรียกใช้ฟังก์ชันเดียวเช่น

ฉันค้นหาอินเทอร์เน็ตมาหลายเดือนแล้ว - หาไม่เจอ (ถามในฟอรัมสองแห่ง - ไม่มีการตอบกลับ)


41
มีเหตุผลมากมายที่ทำให้ฉันต้องค้นหาขนาดของวัตถุใน JavaScript ฉันยังใหม่กับ JavaScript ดังนั้นฉันจึงไม่ปฏิบัติตามแนวปฏิบัติที่ดีที่สุด ฉันยังคงเรียนรู้พวกเขา ฉันได้พัฒนาส่วนขยายของ Firefox ซึ่งฉันแน่ใจว่าใช้หน่วยความจำมากกว่าที่ควรจะเป็น ฉันกำลังทำงานกับวิธีการบางอย่างเพื่อ (หวังว่า) ลดการใช้หน่วยความจำ .. ฉันกำลังพูดถึงวัตถุหลายพันรายการต่อแท็บหลายพันครั้งดังนั้นหน่วยความจำจึงสำคัญ! สิ่งคือฉันต้องการทราบว่าความพยายามลดหน่วยความจำของฉันจริงช่วยในการลดหน่วยความจำ .. และโดยเท่าไหร่

1
หากคุณสร้างส่วนขยาย FF ฉันขอแนะนำให้คุณตรวจสอบในระดับภาษาที่สูงกว่า JS - ดูว่าผลกระทบของ FF เองคืออะไร
annakata

2
ภาษาระดับสูงกว่า JS? ในกรณีนี้จะเป็นเช่นไร?

24
มันไม่ใช่ขนาดที่มีความสำคัญ มันเป็นวิธีที่คุณใช้ PS: ช่างเป็นอะไร!
Thomas Eding

13
@SpencerRuport จำนวนหนึ่งเหตุผลสำหรับการรู้ขนาดของวัตถุสำหรับแอปพลิเคชันที่สามารถใช้งานออฟไลน์ html5 ซึ่งบางครั้งคุณมีพื้นที่เก็บข้อมูล จำกัด
เดวิด

คำตอบ:


181

ฉันได้อีกปัจจัยรหัสในของฉันคำตอบเดิม ฉันลบการสอบถามซ้ำและลบค่าใช้จ่ายที่มีอยู่

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

35
คุณอาจต้องการที่จะคิดว่ากุญแจวัตถุได้เป็นอย่างดี
Zupa

8
ใครก็ตามที่ลงจอดที่นี่กำลังมองหาประเภทที่เล็กที่สุดสำหรับวัตถุประสงค์ของเท็จ / จริงดูเหมือนว่าจะไม่ได้กำหนด / null
zupa

3
"よんもじ".lengthคือ 4 ใน Javascript แต่คุณแน่ใจหรือว่ามันคือ 8 ไบต์เนื่องจากโค้ดของคุณส่งคืนหรือไม่
syockit

8
อ๋อ อักขระใน JavaScript ถูกเก็บไว้ตามข้อกำหนดของ ECMA-262 ฉบับที่ 3 - bclary.com/2004/11/07/#a-4.3.16
thomas-peter

4
ฟังก์ชันนี้ไม่นับการอ้างอิงที่ซ่อนอยู่ในการปิด ยกตัวอย่างเช่นvar a={n:1}; var b={a:function(){return a}}; roughSizeOfObject(b)- ที่นี่bถืออ้างอิงถึงaแต่ผลตอบแทนroughSizeOfObject() 0
Roman Pominov

116

Google Chrome Heap Profiler ช่วยให้คุณตรวจสอบการใช้หน่วยความจำวัตถุ

คุณต้องสามารถค้นหาวัตถุในการติดตามซึ่งอาจเป็นเรื่องยุ่งยาก หากคุณตรึงวัตถุไว้ที่หน้าต่างโกลบอลการค้นหาจากโหมดรายการ "บรรจุ" นั้นค่อนข้างง่าย

ในภาพหน้าจอที่แนบมาฉันสร้างวัตถุที่ชื่อว่า "testObj" บนหน้าต่าง จากนั้นฉันก็อยู่ใน profiler (หลังจากทำการบันทึก) และมันจะแสดงขนาดเต็มของวัตถุและทุกอย่างในนั้นภายใต้ "ขนาดคงที่"

รายละเอียดเพิ่มเติมเกี่ยวกับความผันผวนของหน่วยความจำ

Chrome profiler

ในภาพหน้าจอด้านบนวัตถุแสดงขนาดที่เก็บไว้ 60 ผมเชื่อว่าหน่วยเป็นไบต์ที่นี่


13
คำตอบนี้แก้ปัญหาของฉันพร้อมกับ: developers.google.com/chrome-developer-tools/docs/... เคล็ดลับด่วน: ใช้ Heap Snapshot อย่างรวดเร็วเรียกใช้งานที่คุณสงสัยว่ากำลังรั่วไหลใช้ Heap Snapshot ด่วนใหม่และเลือกcomparisonมุมมองที่ด้านล่าง มันทำให้เห็นได้ชัดว่าวัตถุใดที่ถูกสร้างขึ้นระหว่างภาพรวมสองภาพ
Johnride

1
นี่อาจเป็นทางออกที่สะอาดที่สุด
Luca Steeb

การเปรียบเทียบที่ถูกกล่าวถึงโดย @Johnride ตอนนี้เป็นเมนูแบบเลื่อนลงที่ด้านบน
frandroid

Shallow sizeดูเหมือนว่า 40 สำหรับทั้งวัตถุ{ a:"55c2067aee27593c03b7acbe", b:"55c2067aee27593c03b7acbe", c:null, d:undefined }และ { c:null, d:undefined }ตกลงหรือไม่
efkan

1
คุณสามารถใช้ Google Chrome Heap Profiler จากโหนดได้เช่นกัน หากคุณมีโหนด v8 หรือสูงกว่าให้เริ่มต้นด้วยnode --inspectและใน Chrome ให้ป้อนabout:inspectในแถบ URL และมองหาการเปิดตัวตรวจสอบโหนด สร้างวัตถุของคุณในโหนด CLI จากนั้นทำการสแน็ปช็อตฮีป
Gregor

74

ฉันเพิ่งเขียนสิ่งนี้เพื่อแก้ปัญหาที่คล้ายกัน (ish) มันไม่ได้ทำสิ่งที่คุณกำลังมองหาอย่างแน่นอนเช่นมันไม่ได้คำนึงถึงวิธีที่ล่ามเก็บวัตถุ

แต่ถ้าคุณใช้ V8 มันควรให้การประมาณที่ค่อนข้างโอเคเพราะต้นแบบที่ยอดเยี่ยมและคลาสที่ซ่อนอยู่นั้นเลียค่าโสหุ้ยส่วนใหญ่

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

1
@ Liangliang Zheng - เป็นจุดที่ดีสำหรับการวนซ้ำแบบไม่สิ้นสุดขอบคุณ หวังว่าคุณจะไม่รังเกียจถ้าฉันขออีกครั้งและอัปเดตของฉันหลังเลิกงาน (?)
thomas-peter

ฉันจะทำการทดสอบในคืนนี้กับ node.js และรับค่าสัมประสิทธิ์ที่ดีขึ้น
thomas-peter

บรรทัด 'bytes + = recurse (value [i])' พ่นข้อผิดพลาดใน FF 14.01 ของฉัน: NS_ERROR_FAILURE: คอมโพเนนต์ส่งคืนรหัสความล้มเหลว: 0x80004005 (NS_ERROR_FAILURE) [nsIDOMHTMLInputElement.selectionStart] ในหนึ่งในวัตถุของฉันถ้าฉันลองใช้อันอื่นมันอาจจะไม่ได้เกิดจากข้อผิดพลาดของเบราว์เซอร์หรือรหัสไม่ทำงานสำหรับทุกวัตถุ (อันที่ไม่ทำงานมีฟังก์ชั่น t)
TrySpace

1
จากทอมหนึ่งไปอีกอันหนึ่งสิ่งนี้มีประโยชน์มากในฐานะตัวบ่งชี้คร่าวๆว่าฉันต้องการตัดขอบเอววัตถุของฉันอย่างไร Missus ของคุณค้นพบความสัมพันธ์ของคุณกับ Javascript ไหม? เธอเป็นผู้หญิงที่บำรุงรักษาสูง
Tom W Hall

4
เป็น PHP (อึก) ที่ฉันต้องระวัง - ฉันหยุดรักเธอมานานแล้ว แต่เธอจ่ายค่าใช้จ่าย อย่างไรก็ตามขอบคุณทอมคำติชมที่ชอบนั้นดีกว่าคะแนนชื่อเสียง
thomas-peter

55

บางครั้งฉันใช้สิ่งนี้เพื่อตั้งค่าสถานะวัตถุที่มีขนาดใหญ่มาก ๆ ที่อาจไปยังไคลเอนต์จากเซิร์ฟเวอร์ มันไม่ได้เป็นตัวแทนของหน่วยความจำในรอยเท้า เพียงแค่ทำให้คุณมีค่าใช้จ่ายในการส่งหรือเก็บไว้

ยังทราบว่ามันช้า dev เท่านั้น แต่สำหรับการได้คำตอบ ballpark ด้วยโค้ดหนึ่งบรรทัดมันมีประโยชน์สำหรับฉัน

roughObjSize = JSON.stringify(bigObject).length;

2
จากการทดสอบของฉันวิธีนี้เร็วกว่ากรณีขนาดวัตถุเพราะมันไม่มีการเรียก _.isObject () ที่ช้าจาก lodash นอกจากนี้ขนาดที่ส่งคืนนั้นเทียบเคียงได้กับการประมาณการคร่าวๆ สรุปสาระสำคัญgist.github.com/owenallenaz/ff77fc98081708146495
คลีออน

3
เลวร้ายเกินไปจะแบ่งขึ้นเมื่อวัตถุมีขนาดใหญ่เกินไป :(
cregox

5
ไม่สามารถใช้กับโครงสร้างแบบวงกลมVM1409:1 Uncaught TypeError: Converting circular structure to JSON:( ยังมีประโยชน์แม้ว่า
givanse

นี่ไม่ใช่ขนาดไบนารีเป็นไบต์ แต่ใช้ง่ายเพื่อให้ได้ขนาดโดยประมาณ
datdinhquoc

มันค่อนข้างดีถ้า 1) คุณต้องการเพียงประมาณ ballpark 2) คุณรู้ว่าคุณไม่มีการอ้างอิงแบบวงกลม 3) คุณสามารถละเว้นค่าขนาดใหญ่และแยกพวกมันออกจากกัน ทั้งหมดนี้เป็นจริงในกรณีของฉันดังนั้นทำงานได้อย่างสมบูรณ์แบบฉันมีสตริงใหญ่เพียงเส้นเดียวในที่เดียวซึ่งฉันสามารถวัดความยาวได้
OZZIE

43

นี่เป็นวิธีแก้ปัญหาที่มีขนาดกะทัดรัดกว่าเล็กน้อย:

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

3
นี่คือขนาดเป็น KB หรือไม่? หรือบิต?
vincent thorpe

2
@ vincent-thorpe มีหน่วยเป็นไบต์
Dan

2
สคริปต์ที่ดีต้องการการแก้ไขสำหรับการอ้างอิงแบบวนซ้ำ
Jim Pedid

1
ฉันเพิ่งทดสอบอัลกอริทึมของคุณกับข้อมูลจำนวนมากภายในกระบวนการโหนดมันรายงาน 13GB แต่โหนดนั้นใช้เวลา 22GB ความคิดใดเกี่ยวกับความแตกต่างที่มาจากไหน ไม่มีอะไรในความทรงจำมากขึ้น
Josu Goñi

3
@ JosuGoñiพวกเขาไม่ได้คำนวณว่าวัตถุใช้ตัวเองแค่ไหนตามตัวอักษรเท่านั้น วัตถุทั้งหมดใช้เนื้อที่มากกว่าเพียงแค่ค่าของพวกเขามิฉะนั้นtypeof ...จะไม่ทำงาน
Alexis Wilke

42

มีโมดูล NPM เพื่อรับขนาดวัตถุคุณสามารถติดตั้งได้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));

sizeof (new Date ()) === 0 และ sizeof ({}) === 0 มันตั้งใจหรือไม่
Philipp Claßen

1
@ PhilippClaßenเห็นได้ชัดว่ามันเป็น วัตถุทั้งสองไม่มีคุณสมบัติ
Robert

18

นี่เป็นวิธีแฮ็ก แต่ฉันลองสองครั้งด้วยตัวเลขที่แตกต่างกันและดูเหมือนว่าจะสอดคล้อง

สิ่งที่คุณสามารถทำได้คือการพยายามจัดสรรขนาดใหญ่จำนวนของวัตถุเช่นหนึ่งหรือสองล้านวัตถุทุกชนิดที่คุณต้องการ วางวัตถุในอาร์เรย์เพื่อป้องกันการเก็บขยะจากการปล่อยพวกเขา (โปรดทราบว่าสิ่งนี้จะเพิ่มค่าใช้จ่ายหน่วยความจำเล็กน้อยเพราะอาร์เรย์ แต่ฉันหวังว่ามันไม่สำคัญและนอกเหนือจากถ้าคุณจะกังวลเกี่ยวกับวัตถุที่อยู่ในหน่วยความจำ คุณเก็บมันไว้ที่ไหนสักแห่ง) เพิ่มการแจ้งเตือนก่อนและหลังการจัดสรรและในแต่ละการแจ้งเตือนตรวจสอบจำนวนหน่วยความจำที่กระบวนการ Firefox จะดำเนินการ ก่อนที่คุณจะเปิดหน้าเว็บด้วยการทดสอบตรวจสอบให้แน่ใจว่าคุณมีอินสแตนซ์ Firefox ใหม่ เปิดหน้าบันทึกการใช้หน่วยความจำหลังจากการแจ้งเตือน "ก่อน" จะปรากฏขึ้น ปิดการแจ้งเตือนรอหน่วยความจำที่จะจัดสรร ลบหน่วยความจำใหม่ออกจากหน่วยเดิมและหารด้วยจำนวนการจัดสรร

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

ฉันลองสิ่งนี้ในคอมพิวเตอร์ของฉันและกระบวนการมีหน่วยความจำ 48352K เมื่อการแจ้งเตือน "ก่อน" ถูกแสดง หลังจากการจัดสรร Firefox มีหน่วยความจำ 440236K สำหรับการจัดสรร 2 ล้านนี่คือประมาณ 200 ไบต์สำหรับแต่ละวัตถุ

ฉันลองอีกครั้งด้วยการจัดสรร 1 ล้านรายการและผลลัพธ์ก็ใกล้เคียงกัน: 196 ไบต์ต่อวัตถุ (ฉันสมมติว่ามีการใช้ข้อมูลพิเศษใน 2mill สำหรับอาร์เรย์)

ดังนั้นนี่คือวิธีการแฮ็กที่อาจช่วยคุณได้ JavaScript ไม่ได้ให้วิธีการ "sizeof" ด้วยเหตุผล: การใช้งาน JavaScript แต่ละรายการแตกต่างกัน ใน Google Chrome ตัวอย่างเช่นหน้าเดียวกันใช้ประมาณ 66 ไบต์สำหรับแต่ละวัตถุ (ตัดสินจากตัวจัดการงานอย่างน้อย)


เฮ้ .. ขอบคุณสำหรับเทคนิค ฉันมีสิ่งนั้นตามแผน B ในกรณีที่ไม่มีทางตรงเพื่อไปวัดการใช้หน่วยความจำ

4
การใช้ C และ C ++ แต่ละครั้งก็แตกต่างกันเช่นกัน ;) ขนาดของชนิดข้อมูลใน C หรือ C ++ เป็นการใช้งานเฉพาะ ฉันไม่เห็นเหตุผลที่ JavaScript ไม่สามารถรองรับผู้ประกอบการดังกล่าวแม้ว่าจะไม่ได้ให้บริการตามวัตถุประสงค์เดียวกันหรือมีความหมายเหมือนที่ทำใน C หรือ C ++ (ซึ่งเป็นภาษาระดับต่ำกว่าและวัดขนาดจริงของการแก้ไข - ประเภทข้อมูลขนาดในเวลารวบรวมเมื่อเทียบกับขนาดตัวแปรของวัตถุ JavaScript แบบไดนามิกในเวลาทำงาน)
bambams

12

ขออภัยฉันไม่สามารถแสดงความคิดเห็นดังนั้นฉันเพิ่งทำงานต่อจาก tomwrong รุ่นที่ปรับปรุงนี้จะไม่นับวัตถุมากกว่าหนึ่งครั้งจึงไม่มีการวนซ้ำไม่สิ้นสุด นอกจากนี้ฉันคิดว่ากุญแจของวัตถุควรถูกนับด้วย

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

ฉันคิดว่านี่ถูกต้องมากกว่าเพราะมันนับกุญแจแม้ว่ามันจะนับปุ่ม '__visited__' แล้วก็ตาม
Sam Hasler

ตรวจสอบไม่เพียงพอและคุณจะมีข้อยกเว้นถ้ามีค่าเป็นtypeof value === 'object' null
floribon

นี่เป็นสิ่งที่เห็นได้อย่างรวดเร็วสำหรับวัตถุของฉัน (ซึ่งฉันค่อนข้างมั่นใจว่าจะมีขนาดเกิน 5mb) เมื่อเทียบกับคำตอบที่ติดกันของ @ tomwrong นอกจากนี้ยังมีความแม่นยำมากขึ้น (ตามที่กล่าวว่า 3mb หรือดังนั้น) แต่ก็ยังห่างไกลจากความเป็นจริง เบาะแสใด ๆ เกี่ยวกับสิ่งที่อาจไม่สามารถนับได้?
cregox

ไม่ได้ผลสำหรับฉัน วัตถุlevelมีข้อมูล แต่roughSizeOfObject(level)คืนค่าศูนย์ (ระดับตัวแปรของฉันคือไม่ต้องสับสนกับการโต้แย้งของคุณแน่นอนฉันไม่คิดว่าการแชโดว์แบบตัวแปรควรทำให้เกิดปัญหาที่นี่และเมื่อฉันเปลี่ยนชื่อ 'ระดับ' ในสคริปต์ของคุณฉันจะได้ผลลัพธ์เดียวกัน) : snipboard.io/G7E5yj.jpg
ลัค

10

มีปัญหาเดียวกัน ฉันค้นหาใน Google และฉันต้องการแบ่งปันกับชุมชน stackoverflow โซลูชันนี้

สำคัญ :

ฉันใช้ฟังก์ชั่นที่แบ่งปันโดยYan Qingใน github https://gist.github.com/zensh/4975495

function memorySizeOf(obj) {
    var bytes = 0;

    function sizeOf(obj) {
        if(obj !== null && obj !== undefined) {
            switch(typeof obj) {
            case 'number':
                bytes += 8;
                break;
            case 'string':
                bytes += obj.length * 2;
                break;
            case 'boolean':
                bytes += 4;
                break;
            case 'object':
                var objClass = Object.prototype.toString.call(obj).slice(8, -1);
                if(objClass === 'Object' || objClass === 'Array') {
                    for(var key in obj) {
                        if(!obj.hasOwnProperty(key)) continue;
                        sizeOf(obj[key]);
                    }
                } else bytes += obj.toString().length * 2;
                break;
            }
        }
        return bytes;
    };

    function formatByteSize(bytes) {
        if(bytes < 1024) return bytes + " bytes";
        else if(bytes < 1048576) return(bytes / 1024).toFixed(3) + " KiB";
        else if(bytes < 1073741824) return(bytes / 1048576).toFixed(3) + " MiB";
        else return(bytes / 1073741824).toFixed(3) + " GiB";
    };

    return formatByteSize(sizeOf(obj));
};


var sizeOfStudentObject = memorySizeOf({Student: {firstName: 'firstName', lastName: 'lastName', marks: 10}});
console.log(sizeOfStudentObject);

คุณคิดยังไงกับเรื่องนี้?


3
ฟังก์ชั่นนี้พลาด ถ้าฉันเพิ่มฟังก์ชั่นวัตถุจะไม่แสดงให้ใหญ่กว่านี้เลย
Don Rhummy

ไม่นับกุญแจ
ebg11

7

ฉันต้องการทราบว่าความพยายามลดหน่วยความจำของฉันจริงช่วยในการลดหน่วยความจำ

ติดตามความคิดเห็นนี้ต่อไปนี้คือสิ่งที่คุณควรทำ: พยายามสร้างปัญหาหน่วยความจำ - เขียนรหัสที่สร้างวัตถุเหล่านี้ทั้งหมดและเพิ่มขีด จำกัด สูงสุดอย่างไม่น่าเชื่อจนกว่าคุณจะพบปัญหา (เบราว์เซอร์ขัดข้องเบราว์เซอร์หยุดทำงาน หน่วยความจำผิดพลาด) เป็นการดีที่คุณควรทำซ้ำการทดสอบนี้กับเบราว์เซอร์ที่แตกต่างกันและระบบปฏิบัติการที่แตกต่างกัน

ขณะนี้มีสองตัวเลือก: ตัวเลือก 1 - คุณไม่ประสบความสำเร็จในการสร้างปัญหาหน่วยความจำ ดังนั้นคุณไม่ต้องกังวลอะไร คุณไม่มีปัญหาหน่วยความจำและโปรแกรมของคุณใช้ได้

ตัวเลือก 2- คุณได้รับปัญหาหน่วยความจำ ตอนนี้ถามตัวเองว่าข้อ จำกัด ที่เกิดปัญหานั้นสมเหตุสมผลหรือไม่ (ในคำอื่น ๆ : เป็นไปได้ไหมว่าจำนวนวัตถุนี้จะถูกสร้างขึ้นตามการใช้งานปกติของรหัสของคุณ) ถ้าคำตอบคือ 'ไม่' คุณก็ไม่เป็นไร มิฉะนั้นตอนนี้คุณจะรู้ว่าวัตถุของคุณสามารถสร้างรหัสได้จำนวนเท่าใด ทำใหม่อัลกอริธึมที่ไม่ละเมิดขีด ​​จำกัด นี้


จากจุดตั้งหน่วยความจำส่วนขยายของฉันจะเพิ่มวัตถุจำนวนมากสำหรับแต่ละหน้า / แท็บที่เปิดใน Firefox "หมายเลข" เป็นสัดส่วนกับขนาดของหน้า สมมติว่าผู้ใช้ "พลังงาน" มีที่ใดก็ได้ระหว่าง 15 - 20 แท็บที่เปิดอยู่และหากหน้าเว็บมีเนื้อหาจำนวนมากเบราว์เซอร์จะช้าและหงุดหงิดไม่ตอบสนองหลังจากผ่านไประยะหนึ่ง สิ่งนี้เกิดขึ้นแม้ว่าฉันจะไม่พยายามเน้นแอพ ฉันมีแผนที่จะเขียนโค้ดที่ฉันคิดว่าจะช่วยลดการสร้างวัตถุจำนวนมาก ฉันแค่อยากจะแน่ใจว่าไม่มี ของวัตถุลดลงเป็นจำนวนสิ่งที่คุ้มค่า

@enthil: แต่ขนาดวัตถุไม่มีความหมายเว้นแต่คุณจะทราบจำนวนหน่วยความจำที่มีอยู่ เนื่องจากจำนวนหน่วยความจำน่าจะยังคงเป็นปริศนาอยู่การพูดในรูปของ #objects นั้นมีประโยชน์เช่นเดียวกับการพูดในรูปของ #bytes
Itay Maman

5

หากข้อกังวลหลักของคุณคือการใช้หน่วยความจำของส่วนขยาย Firefox ของคุณฉันขอแนะนำให้ตรวจสอบกับนักพัฒนา Mozilla

Mozilla ให้บริการเกี่ยวกับวิกิพีเดียของรายการของเครื่องมือในการวิเคราะห์การรั่วไหลของหน่วยความจำ


5

ไลบรารี Javascript นี้sizeof.jsทำสิ่งเดียวกัน รวมไว้เช่นนี้

<script type="text/javascript" src="sizeof.js"></script>

ฟังก์ชั่น sizeof รับวัตถุเป็นพารามิเตอร์และส่งกลับขนาดโดยประมาณเป็นไบต์ ตัวอย่างเช่น:

// define an object
var object =
    {
      'boolean' : true,
      'number'  : 1,
      'string'  : 'a',
      'array'   : [1, 2, 3]
    };

// determine the size of the object
var size = sizeof(object);

ฟังก์ชัน sizeof สามารถจัดการวัตถุที่มีการอ้างอิงหลายรายการไปยังวัตถุอื่นและการอ้างอิงแบบเรียกซ้ำ

ตีพิมพ์ครั้งแรกที่นี่


สิ่งนี้ช้าลงและดูเหมือนว่า "แม่นยำน้อยกว่า" @liangliang ในกรณีที่ฉันใช้งาน
cregox


2

ขอบคุณมากสำหรับทุกคนที่ทำงานเกี่ยวกับโค้ดสำหรับสิ่งนี้!

ฉันแค่อยากจะเพิ่มว่าฉันกำลังมองหาสิ่งเดียวกัน แต่ในกรณีของฉันมันมีไว้สำหรับจัดการแคชของวัตถุที่ประมวลผลเพื่อหลีกเลี่ยงการแยกวิเคราะห์และประมวลผลวัตถุจากการโทร ajax ที่อาจหรือไม่แคช โดยเบราว์เซอร์ สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับวัตถุที่ต้องการการประมวลผลจำนวนมากโดยปกติแล้วสิ่งใดก็ตามที่ไม่ได้อยู่ในรูปแบบ JSON แต่อาจมีค่าใช้จ่ายสูงมากที่จะเก็บสิ่งเหล่านี้ไว้ในโครงการขนาดใหญ่หรือแอป / ส่วนขยายที่เหลืออยู่เป็นเวลานาน เวลา.

อย่างไรก็ตามฉันใช้เพื่อสิ่งที่ชอบ:

var myCache = {
    cache: {},
    order: [],
    size: 0,
    maxSize: 2 * 1024 * 1024, // 2mb

    add: function(key, object) {
        // Otherwise add new object
        var size = this.getObjectSize(object);
        if (size > this.maxSize) return; // Can't store this object

        var total = this.size + size;

        // Check for existing entry, as replacing it will free up space
        if (typeof(this.cache[key]) !== 'undefined') {
            for (var i = 0; i < this.order.length; ++i) {
                var entry = this.order[i];
                if (entry.key === key) {
                    total -= entry.size;
                    this.order.splice(i, 1);
                    break;
                }
            }
        }

        while (total > this.maxSize) {
            var entry = this.order.shift();
            delete this.cache[entry.key];
            total -= entry.size;
        }

        this.cache[key] = object;
        this.order.push({ size: size, key: key });
        this.size = total;
    },

    get: function(key) {
        var value = this.cache[key];
        if (typeof(value) !== 'undefined') { // Return this key for longer
            for (var i = 0; i < this.order.length; ++i) {
                var entry = this.order[i];
                if (entry.key === key) {
                    this.order.splice(i, 1);
                    this.order.push(entry);
                    break;
                }
            }
        }
        return value;
    },

    getObjectSize: function(object) {
        // Code from above estimating functions
    },
};

มันเป็นตัวอย่างที่ง่ายและอาจมีข้อผิดพลาดบางอย่าง แต่มันให้ความคิดเนื่องจากคุณสามารถใช้มันเพื่อจับวัตถุแบบสแตติก (เนื้อหาจะไม่เปลี่ยนแปลง) ด้วยความฉลาดระดับหนึ่ง สิ่งนี้สามารถลดความต้องการการประมวลผลที่มีราคาแพงอย่างมากที่วัตถุจะต้องมีการผลิตในสถานที่แรก


1
function sizeOf(parent_data, size)
{
    for (var prop in parent_data)
    {
        let value = parent_data[prop];

        if (typeof value === 'boolean')
        {
            size += 4;
        }
        else if (typeof value === 'string')
        {
            size += value.length * 2;
        }
        else if (typeof value === 'number')
        {
             size += 8;
        }
        else
        {      
            let oldSize = size;
            size += sizeOf(value, oldSize) - oldSize;
        }
    }

    return size;
}


function roughSizeOfObject(object)
{   
    let size = 0;
    for each (let prop in object)
    {    
        size += sizeOf(prop, 0);
    } // for..
    return size;
}

1

ฉันใช้แท็บไทม์ไลน์ของเครื่องมือ dev ของ Chrome ยกตัวอย่างวัตถุจำนวนมากขึ้นและรับการประมาณที่ดีเช่นนั้น คุณสามารถใช้ html แบบนี้ด้านล่างเป็นสำเร็จรูปและปรับเปลี่ยนเพื่อจำลองลักษณะของวัตถุของคุณได้ดีขึ้น (จำนวนและประเภทของคุณสมบัติ ฯลฯ ... ) คุณอาจต้องการคลิกที่ไอคอนถังขยะที่ด้านล่างของแท็บเครื่องมือ dev นั้นก่อนและหลังการทำงาน

<html>
<script>
var size = 1000*100
window.onload = function() {
  document.getElementById("quantifier").value = size
}

function scaffold()
{
  console.log("processing Scaffold...");
  a = new Array
}

function start()
{
  size = document.getElementById("quantifier").value
  console.log("Starting... quantifier is " + size);
  console.log("starting test")
  for (i=0; i<size; i++){
    a[i]={"some" : "thing"}
  }
  console.log("done...")
}

function tearDown()
{
  console.log("processing teardown");
  a.length=0
}

</script>
<body>
    <span style="color:green;">Quantifier:</span>
    <input id="quantifier" style="color:green;" type="text"></input>
    <button onclick="scaffold()">Scaffold</button>
    <button onclick="start()">Start</button>
    <button onclick="tearDown()">Clean</button>
    <br/>
</body>
</html>

การเพิ่มจำนวนวัตถุ 2 ล้านชิ้นในทรัพย์สินเพียงหนึ่งรายการ (เช่นเดียวกับในรหัสด้านบน) นำไปสู่การคำนวณคร่าวๆที่ 50 ไบต์ต่อวัตถุบน Chromium ของฉันในตอนนี้ การเปลี่ยนรหัสเพื่อสร้างสตริงแบบสุ่มต่อวัตถุจะเพิ่มจำนวน 30 ไบต์ต่อวัตถุเป็นต้นหวังว่าจะช่วยได้


1

หากคุณจำเป็นต้องตรวจสอบโปรแกรม aprox ขนาดของวัตถุที่คุณสามารถตรวจสอบไลบรารี่นี้ได้ด้วยhttp://code.stephenmorley.org/javascript/finding-the-memory-usage-of-objects/ไลที่ฉันสามารถใช้กับขนาดวัตถุได้

มิฉะนั้นฉันแนะนำให้ใช้ Chrome / Firefox Heap Profiler


-3

ฉันเชื่อว่าคุณลืมใส่ 'อาร์เรย์'

  typeOf : function(value) {
        var s = typeof value;
        if (s === 'object')
        {
            if (value)
            {
                if (typeof value.length === 'number' && !(value.propertyIsEnumerable('length')) && typeof value.splice === 'function')
                {
                    s = 'array';
                }
            }
            else
            {
                s = 'null';
            }
        }
        return s;
    },

   estimateSizeOfObject: function(value, level)
    {
        if(undefined === level)
            level = 0;

        var bytes = 0;

        if ('boolean' === typeOf(value))
            bytes = 4;
        else if ('string' === typeOf(value))
            bytes = value.length * 2;
        else if ('number' === typeOf(value))
            bytes = 8;
        else if ('object' === typeOf(value) || 'array' === typeOf(value))
        {
            for(var i in value)
            {
                bytes += i.length * 2;
                bytes+= 8; // an assumed existence overhead
                bytes+= estimateSizeOfObject(value[i], 1)
            }
        }
        return bytes;
    },

   formatByteSize : function(bytes)
    {
        if (bytes < 1024)
            return bytes + " bytes";
        else
        {
            var floatNum = bytes/1024;
            return floatNum.toFixed(2) + " kb";
        }
    },

1
ใน JS อาร์เรย์คือวัตถุ อาจมีการปรับให้เหมาะสมบางอย่างในการใช้งาน แต่อาร์เรย์แนวคิดและวัตถุเหมือนกัน
Kris Walker

-8

ฉันรู้นี่ไม่ใช่วิธีที่ถูกต้องในการทำสิ่งนี้ แต่มันได้ช่วยฉันสองสามครั้งในอดีตที่จะได้ขนาดวัตถุโดยประมาณ:

เขียนวัตถุ / การตอบสนองของคุณไปยังคอนโซลหรือแท็บใหม่คัดลอกผลลัพธ์ไปยังไฟล์แผ่นจดบันทึกใหม่บันทึกและตรวจสอบขนาดไฟล์ ไฟล์ notepad นั้นมีขนาดเพียงไม่กี่ไบต์ดังนั้นคุณจะได้ขนาดวัตถุไฟล์ที่ถูกต้องพอสมควร


4
นี่เป็นสิ่งที่ผิดอย่างสิ้นเชิง ตัวอย่างเช่นพิจารณาเลขที่ 1/3 = 0.3333333333333333 จะมีขนาด 18 ไบต์โดยใช้วิธีการของคุณ
korCZis

2
ผมบอกว่ามันเป็นตัวอย่าง บางครั้งคุณไม่สนใจว่าจะเป็น 1MB หรือ 1.00001MB คุณแค่อยากรู้ค่าประมาณแล้ววิธีนี้ก็ใช้ได้ดีมาก
Jeffrey Roosendaal

วิธีแก้ปัญหาหน้าด้าน X]
Lapys
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.