Rumah >hujung hadapan web >tutorial js >Apakah Tepatnya Had Memori Node.js?

Apakah Tepatnya Had Memori Node.js?

Susan Sarandon
Susan Sarandonasal
2024-12-25 04:35:18853semak imbas

What Exactly Is the Memory Limit of Node.js?

Kemahiran dalam API Node.js boleh membantu anda berjalan dengan pantas, tetapi pemahaman mendalam tentang jejak memori program Node.js boleh membawa anda lebih jauh.

Mari kita mulakan perkara ini dengan melihat penggunaan memori kita dengan process.memoryUsage(), mengemas kini setiap saat:

setInterval(() => { console.log('Memory Usage:', process.memoryUsage()); }, 1000);

Memandangkan output adalah dalam bait, ia tidak mesra pengguna. Mari kita rapikan dengan memformatkan penggunaan memori menjadi MB:

function formatMemoryUsageInMB(memUsage) {
    return {
        rss: convertToMB(memUsage.rss),
        heapTotal: convertToMB(memUsage.heapTotal),
        heapUsed: convertToMB(memUsage.heapUsed),
        external: convertToMB(memUsage.external)
    };
}

const convertToMB = value => {
    return (value / 1024 / 1024).toFixed(2) + ' MB';
};

const logInterval = setInterval(() => {
    const memoryUsageMB = formatMemoryUsageInMB(process.memoryUsage());
    console.log(`Memory Usage (MB):`, memoryUsageMB);
}, 1000);

Kini, kita boleh mendapatkan output berikut setiap saat:

Memory Usage (MB): {
  rss: '30.96 MB', // The actual OS memory used by the entire program, including code, data, shared libraries, etc.
  heapTotal: '6.13 MB', // The memory area occupied by JS objects, arrays, etc., dynamically allocated by Node.js
                      // V8 divides the heap into young and old generations for different garbage collection strategies
  heapUsed: '5.17 MB',
  external: '0.39 MB'
}

Memory Usage (MB): {
  rss: '31.36 MB',
  heapTotal: '6.13 MB',
  heapUsed: '5.23 MB',
  external: '0.41 MB'
}

Kita semua tahu bahawa penggunaan memori enjin V8 adalah terhad, bukan sahaja oleh dasar pengurusan memori dan peruntukan sumber OS tetapi juga oleh tetapannya sendiri.

Menggunakan os.freemem(), kita boleh melihat berapa banyak memori kosong yang OS ada, tetapi itu tidak bermakna semuanya boleh direbut oleh program Node.js.

console.log('Free memory:', os.freemem());

Untuk sistem 64-bit, saiz ruang lama maksimum lalai Node.js V8 ialah sekitar 1.4GB. Ini bermakna walaupun OS anda mempunyai lebih banyak memori yang tersedia, V8 tidak akan menggunakan lebih daripada had ini secara automatik.

Petua: Had ini boleh ditukar dengan menetapkan pembolehubah persekitaran atau menentukan parameter apabila memulakan Node.js. Contohnya, jika anda mahu V8 menggunakan timbunan yang lebih besar, anda boleh menggunakan pilihan --max-old-space-size:

node --max-old-space-size=4096 your_script.js

Nilai ini perlu ditetapkan berdasarkan situasi dan senario sebenar anda. Contohnya, jika anda mempunyai mesin yang mempunyai banyak memori, digunakan secara bersendirian, dan anda mempunyai banyak mesin memori kecil yang digunakan dalam cara yang diedarkan, tetapan untuk nilai ini pasti akan berbeza.

Mari kita jalankan ujian dengan memasukkan tatasusunan dengan data selama-lamanya sehingga memori melimpah dan lihat bila ia berlaku.

const array = [];
while (true) {
    for (let i = 0; i < 100000; i++) {
        array.push(i);
    }
    const memoryUsageMB = formatMemoryUsageInMB(process.memoryUsage());
    console.log(`Memory Usage (MB):`, memoryUsageMB);
}

Inilah yang kami dapat apabila kami menjalankan program secara langsung. Selepas menambah data seketika, program ranap.

Memory Usage (MB): {
  rss: '2283.64 MB',
  heapTotal: '2279.48 MB',
  heapUsed: '2248.73 MB',
  external: '0.40 MB'
}
Memory Usage (MB): {
  rss: '2283.64 MB',
  heapTotal: '2279.48 MB',
  heapUsed: '2248.74 MB',
  external: '0.40 MB'
}


#
# Fatal error in , line 0
# Fatal JavaScript invalid size error 169220804
#
#
#
#FailureMessage Object: 0x7ff7b0ef8070

Keliru? Bukankah hadnya 1.4G? Mengapa ia menggunakan lebih 2G? Sebenarnya, had 1.4GB Node.js ialah had sejarah enjin V8, terpakai pada versi awal V8 dan konfigurasi tertentu. Dalam Node.js dan V8 moden, Node.js melaraskan penggunaan memorinya secara automatik berdasarkan sumber sistem. Dalam sesetengah kes, ia mungkin menggunakan lebih daripada 1.4GB, terutamanya apabila berurusan dengan set data yang besar atau menjalankan operasi intensif memori.

Apabila kami menetapkan had memori kepada 512M, ia melimpah apabila rss mencecah sekitar 996 MB.

Memory Usage (MB): {
  rss: '996.22 MB',
  heapTotal: '993.22 MB',
  heapUsed: '962.08 MB',
  external: '0.40 MB'
}
Memory Usage (MB): {
  rss: '996.23 MB',
  heapTotal: '993.22 MB',
  heapUsed: '962.09 MB',
  external: '0.40 MB'
}

<--- Last few GCs --->

[22540:0x7fd27684d000]     1680 ms: Mark-sweep 643.0 (674.4) -> 386.8 (419.4) MB, 172.2 / 0.0 ms  (average mu = 0.708, current mu = 0.668) allocation failure; scavenge might not succeed
[22540:0x7fd27684d000]     2448 ms: Mark-sweep 962.1 (993.2) -> 578.1 (610.7) MB, 240.7 / 0.0 ms  (average mu = 0.695, current mu = 0.687) allocation failure; scavenge might not succeed


<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory

Ringkasnya, untuk menjadi lebih tepat, had ingatan Node.js merujuk kepada had ingatan timbunan, iaitu memori maksimum yang boleh diduduki oleh objek JS, tatasusunan, dsb., yang diperuntukkan oleh V8.

Adakah saiz memori timbunan menentukan jumlah memori yang boleh diduduki oleh proses Node.js? Tidak! Teruskan membaca.

Bolehkah saya Meletakkan Fail 3GB ke dalam Memori Node.js?

Kami melihat dalam ujian bahawa tatasusunan hanya boleh menampung sedikit lebih 2GB sebelum program ranap. Jadi, jika saya mempunyai fail 3GB, bolehkah saya memasukkannya ke dalam memori Node.js sekaligus?

Anda boleh!

Kami melihat memori luaran melalui process.memoryUsage(), yang diduduki oleh proses Node.js tetapi tidak diperuntukkan oleh V8. Selagi anda meletakkan fail 3GB di sana, tiada had memori. Bagaimana? Anda boleh menggunakan Penampan. Penampan ialah modul sambungan C Node.js yang memperuntukkan memori menggunakan C , bukan objek dan data JS.

Berikut ialah demo:

setInterval(() => { console.log('Memory Usage:', process.memoryUsage()); }, 1000);

Walaupun anda memperuntukkan 3GB memori, program kami masih berjalan lancar, dan program Node.js kami telah menduduki lebih 5GB memori kerana memori luaran ini tidak dihadkan oleh Node.js tetapi oleh had sistem pengendalian pada memori yang diperuntukkan kepada benang (jadi anda tidak boleh menjadi liar, malah Penimbal boleh kehabisan memori; intipatinya adalah untuk mengendalikan data besar dengan Strim).

Dalam Node.js, kitaran hayat objek Penampan terikat pada objek JavaScript. Apabila rujukan JavaScript kepada objek Penampan dialih keluar, pengumpul sampah V8 menandakan objek sebagai boleh dikitar semula, tetapi memori asas objek Penampan tidak dikeluarkan serta-merta. Biasanya, apabila pemusnah sambungan C dipanggil (contohnya, semasa proses pengumpulan sampah dalam Node.js), bahagian memori ini dikeluarkan. Walau bagaimanapun, proses ini mungkin tidak disegerakkan sepenuhnya dengan kutipan sampah V8.

function formatMemoryUsageInMB(memUsage) {
    return {
        rss: convertToMB(memUsage.rss),
        heapTotal: convertToMB(memUsage.heapTotal),
        heapUsed: convertToMB(memUsage.heapUsed),
        external: convertToMB(memUsage.external)
    };
}

const convertToMB = value => {
    return (value / 1024 / 1024).toFixed(2) + ' MB';
};

const logInterval = setInterval(() => {
    const memoryUsageMB = formatMemoryUsageInMB(process.memoryUsage());
    console.log(`Memory Usage (MB):`, memoryUsageMB);
}, 1000);

Ringkasnya: Penggunaan memori Node.js terdiri daripada penggunaan memori timbunan JS (ditentukan oleh kutipan sampah V8) peruntukan memori oleh C

Mengapa Memori Timbunan Diasingkan kepada Generasi Baru dan Lama?

Strategi pengumpulan sampah generasi sangat lazim dalam pelaksanaan bahasa pengaturcaraan moden! Strategi serupa seperti Pengumpulan Sampah Generasi boleh didapati dalam Ruby,.NET dan Java. Apabila kutipan sampah berlaku, ia selalunya membawa kepada situasi "hentikan dunia", yang pastinya memberi kesan kepada prestasi program. Walau bagaimanapun, reka bentuk ini difikirkan dengan pengoptimuman prestasi.

  • Jangka hayat Objek Berbeza Semasa pembangunan program, sebahagian besar pembolehubah adalah sementara, berfungsi untuk memenuhi tugas pengiraan tempatan tertentu. Pembolehubah sedemikian lebih sesuai untuk GC Minor, iaitu, GC generasi baharu. Objek dalam memori generasi baharu adalah tertakluk kepada pengumpulan sampah melalui algoritma Scavenge. Algoritma Scavenge membahagikan memori timbunan kepada dua bahagian, iaitu Dari dan Kepada (pertukaran ruang-untuk-masa klasik. Terima kasih kepada masa kelangsungan hidup yang singkat, mereka tidak menggunakan sejumlah besar memori).

Apabila memori diperuntukkan, ia berlaku dalam Daripada. Semasa pengumpulan sampah, objek hidup dalam Daripada diperiksa dan disalin ke Kepada, diikuti dengan pelepasan objek bukan hidup. Dalam pusingan pengumpulan seterusnya, objek hidup dalam To direplikasi kepada From, di mana titik To berubah menjadi From dan sebaliknya. Dengan setiap kitaran kutipan sampah, Dari dan Kepada ditukar. Algoritma ini hanya mereplikasi objek hidup semasa proses penyalinan dan dengan itu mengelakkan penjanaan serpihan memori.
Jadi, bagaimanakah keaktifan sesuatu pembolehubah ditentukan? Analisis kebolehcapaian memainkan peranan. Pertimbangkan objek berikut sebagai contoh:

  • globalObject: Objek global.
  • obj1: Objek yang dirujuk secara langsung oleh globalObject.
  • obj2: Objek yang dirujuk oleh obj1.
  • obj3: Objek terpencil tanpa sebarang rujukan daripada objek lain.

Dalam konteks analisis kebolehcapaian:

  • globalObject, sebagai objek akar, sememangnya boleh dicapai.
  • obj1, kerana dirujuk oleh globalObject, juga boleh dicapai.
  • obj2, seperti yang dirujuk oleh obj1, juga boleh dicapai.
  • Sebaliknya, obj3, yang tidak mempunyai sebarang laluan rujukan kepada objek akar atau objek lain yang boleh dicapai, dianggap tidak boleh dicapai dan dengan itu layak untuk dikitar semula.

Diakui, pengiraan rujukan boleh berfungsi sebagai cara tambahan. Namun begitu, dengan adanya rujukan pekeliling, ia gagal untuk memastikan keaktifan sebenar objek dengan tepat.

Dalam ingatan generasi lama, objek biasanya kurang aktif. Walau bagaimanapun, apabila memori generasi lama menjadi penuh, ia mencetuskan pembersihan memori generasi lama (Major GC) melalui algoritma Mark-Sweep.

Algoritma Mark-Sweep terdiri daripada dua fasa: menanda dan menyapu. Dalam fasa penandaan, enjin V8 merentasi semua objek dalam timbunan dan menandai objek hidup. Dalam fasa menyapu, hanya objek yang tidak bertanda dibersihkan. Kebaikan algoritma ini ialah fasa penyapuan mengambil masa yang agak sedikit kerana bahagian objek mati dalam generasi lama adalah agak kecil. Walau bagaimanapun, kelemahannya ialah ia hanya mengosongkan tanpa padat, yang mungkin mengakibatkan ruang ingatan terputus, menjadikannya menyusahkan untuk memperuntukkan memori untuk objek besar.

Kekurangan ini menimbulkan pemecahan memori, memerlukan penggunaan algoritma lain, Mark-Compact. Algoritma ini mengalihkan semua objek hidup ke satu hujung dan kemudian menghapuskan ruang memori yang tidak sah di sebelah kanan sempadan dalam satu gerakan, dengan itu memperoleh ruang memori tersedia yang lengkap dan berterusan. Ia menyelesaikan isu pemecahan memori yang mungkin disebabkan oleh algoritma Mark-Sweep, walaupun dengan kos memakan lebih banyak masa dalam menggerakkan sejumlah besar objek hidup.

Jika anda rasa siaran ini berguna, sila berikan acungan tangan. :D

Atas ialah kandungan terperinci Apakah Tepatnya Had Memori Node.js?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn