Analisis ringkas tentang masalah kebocoran memori dalam Node.js_node.js

WBOY
Lepaskan: 2016-05-16 15:53:19
asal
1086 orang telah melayarinya

Artikel ini adalah yang pertama dalam satu siri artikel Musim Percutian A Node.JS yang dibawakan kepada anda oleh pasukan Identity Mozilla, yang mengeluarkan versi beta pertama Persona bulan lepas. Apabila membangunkan Persona, kami membina satu siri alatan, daripada penyahpepijatan, penyetempatan, kepada pengurusan pergantungan dan banyak lagi. Dalam siri artikel ini kami akan berkongsi pengalaman kami dan alatan ini dengan komuniti, yang akan berguna kepada sesiapa sahaja yang ingin membina perkhidmatan ketersediaan tinggi dengan Node.js. Kami berharap anda menikmati artikel ini dan berharap untuk melihat pemikiran dan sumbangan anda.

Kami akan mulakan dengan artikel topikal tentang masalah substantif dalam Node.js: kebocoran memori. Kami akan memperkenalkan node-memwatch — perpustakaan yang membantu mencari dan mengasingkan kebocoran memori dalam Node.


Kenapa awak minta masalah?

Soalan yang paling kerap ditanya tentang menjejaki kebocoran memori ialah, "Mengapa menyusahkan diri sendiri?". Tidakkah ada lagi isu mendesak yang perlu ditangani terlebih dahulu? Mengapa tidak memilih untuk memulakan semula perkhidmatan dari semasa ke semasa, atau memperuntukkan lebih banyak RAM kepadanya? Untuk menjawab soalan ini, kami mencadangkan tiga cadangan berikut:

1. Mungkin anda tidak mengambil berat tentang jejak memori yang semakin meningkat, tetapi V8 tidak (V8 ialah enjin masa jalan Node). Apabila kebocoran memori berkembang, V8 menjadi lebih agresif dengan pengumpul sampah, yang boleh menjadikan aplikasi anda berjalan lebih perlahan. Oleh itu, pada Node, kebocoran memori akan merosakkan prestasi program.

2. Kebocoran memori boleh mencetuskan jenis kegagalan lain. Kod yang membocorkan memori boleh terus merujuk sumber terhad. Anda mungkin kehabisan deskriptor fail anda mungkin juga tiba-tiba tidak dapat membuat sambungan pangkalan data baharu. Masalah jenis ini mungkin timbul lama sebelum apl anda kehabisan memori, tetapi ia masih boleh menyebabkan anda menghadapi masalah.

3. Akhirnya, apl anda akan ranap lambat laun, dan ia pasti akan berlaku apabila apl anda semakin popular. Semua orang akan mentertawakan anda dan mengejek anda di Berita Hacker, yang akan menjadikan anda tragedi.

Di manakah sarang semut yang memecahkan benteng beribu batu?

Apabila membina aplikasi yang kompleks, kebocoran memori mungkin berlaku di banyak tempat. Penutupan mungkin yang paling terkenal dan terkenal. Oleh kerana penutupan mengekalkan rujukan kepada perkara dalam skopnya, di sinilah kebocoran memori biasanya datang.

Kebocoran penutupan selalunya ditemui hanya apabila seseorang mencarinya. Tetapi dalam dunia tak segerak Node, kami sentiasa menjana penutupan melalui fungsi panggil balik pada bila-bila masa dan di mana-mana sahaja. Jika fungsi panggil balik ini tidak digunakan serta-merta selepas penciptaan, memori yang diperuntukkan akan terus berkembang dan kod yang kelihatan tidak mempunyai kebocoran memori akan bocor. Dan masalah seperti ini lebih sukar dicari.

Aplikasi anda juga boleh menyebabkan kebocoran memori disebabkan masalah dalam kod huluan. Mungkin anda boleh mencari kod yang membocorkan memori, tetapi anda mungkin hanya melihat kod sempurna anda dan tertanya-tanya bagaimana ia bocor!


Kebocoran memori yang sukar dikesan inilah yang membuatkan kita mahukan alat seperti nod-memwatch. Legenda mengatakan bahawa beberapa bulan yang lalu, Lloyd Hilaiel kami sendiri mengunci dirinya di dalam bilik kecil selama dua hari, cuba menjejaki kebocoran ingatan yang menjadi jelas di bawah ujian tekanan. (By the way, nantikan artikel Lloyd yang akan datang tentang ujian beban)

Selepas dua hari bekerja keras, dia akhirnya menemui punca dalam kernel Node: pendengar acara dalam http.ClientRequest tidak dikeluarkan. (Tampalan yang akhirnya membetulkan masalah itu hanya dua tetapi surat penting). Pengalaman yang menyakitkan inilah yang mendorong Lloyd menulis alat yang boleh membantu mencari kebocoran ingatan.

Alat mengesan kebocoran memori

Terdapat banyak alat yang berguna dan sentiasa menambah baik untuk mengesan kebocoran memori dalam aplikasi Node.js. Berikut adalah sebahagian daripadanya:

  • nod-mtrace Jimb Esser, yang menggunakan alat mtrace GCC untuk menganalisis penggunaan timbunan.
  • node-heap-dump Dave Pacheco mengambil gambar timbunan V8 dan mensirikan semuanya ke dalam fail JSON yang besar. Ia juga mengandungi alatan JavaScript untuk menganalisis hasil syot kilat kajian.
  • v8-profiler dan nod-inspector Danny Coates menyediakan profil V8 yang digabungkan dalam Node dan antara muka nyahpepijat berdasarkan WebKit Web Inspector.
  • Felix Gnass tidak melumpuhkan cawangan carta penjaga .
  • Felix Geisendorfer Tutorial Kebocoran Memori Nod ialah tutorial ringkas dan menarik tentang cara menggunakan v8-profiler dan nod-debugger. Ia juga merupakan panduan teknikal penyahpepijatan kebocoran memori Node.js yang paling canggih.
  • Platform SmartOS Joyent, yang menyediakan sejumlah besar alatan untuk menyahpepijat kebocoran memori Node.js.

Kami semua menyukai alatan di atas, tetapi tiada satu pun daripada mereka yang sesuai dengan senario kami. Pemeriksa Web bagus untuk membangunkan aplikasi, tetapi sukar digunakan dalam senario penggunaan panas, terutamanya apabila berbilang pelayan dan sub-proses terlibat. Begitu juga, kebocoran memori yang berlaku semasa operasi beban tinggi jangka panjang juga sukar untuk dihasilkan semula. Alat seperti dtrace dan libumem, walaupun mengagumkan, tidak tersedia pada semua sistem pengendalian.

Enternode-memwatch

Kami memerlukan perpustakaan penyahpepijatan merentas platform yang tidak memerlukan peranti memberitahu kami bila program kami mungkin mengalami kebocoran memori dan akan membantu kami mencari tempat kebocoran itu wujud. Jadi kami melaksanakan nod-memwatch.

Ia memberikan kita tiga perkara:

Pemancar peristiwa 'kebocoran'
 

   memwatch.on('leak', function(info) {
  // look at info to find out about what might be leaking
  });
Salin selepas log masuk

'pemancar peristiwa status

       

  var memwatch = require('memwatch');
  memwatch.on('stats', function(stats) {
  // do something with post-gc memory usage stats
  });
Salin selepas log masuk

Klasifikasi kawasan ingatan timbunan

  var hd = new memwatch.HeapDiff();
  // your code here ...
  var diff = hd.end();
Salin selepas log masuk

Dan terdapat juga fungsi yang boleh mencetuskan pemungut sampah yang sangat berguna semasa ujian. Okay, empat semuanya.
 

 var stats = memwatch.gc();
Salin selepas log masuk

memwatch.on('stats', ...): Statistik timbunan pasca GC

nod-memwatch boleh mengeluarkan sampel penggunaan memori berikutan pengumpulan sampah yang lengkap dan pemadatan memori sebelum sebarang objek JS diperuntukkan. (Ia menggunakan cangkuk post-gc V8, V8::AddGCEpilogueCallback, untuk mengumpul maklumat penggunaan timbunan setiap kali kutipan sampah dicetuskan)

Statistik termasuk:

  • trend_penggunaan (trend penggunaan)
  • pangkalan_semasa (asas semasa)
  • anggaran_asas (asas dijangka)
  • num_full_gc (bilangan kutipan sampah lengkap)
  • num_inc_gc (peningkatan bilangan kutipan sampah)
  • heap_compactions (bilangan pemampatan memori)
  • min (minimum)
  • maks (maksimum)

Berikut ialah contoh rupa data untuk aplikasi dengan kebocoran memori. Carta di bawah menjejaki penggunaan memori dari semasa ke semasa. Garis hijau gila menunjukkan proses.memoryUsage() yang dilaporkan. Garis merah menunjukkan current_base yang dilaporkan oleh node_memwatch. Kotak di sebelah kiri bawah menunjukkan maklumat tambahan.

2015623152204606.png (572×441)

Ambil perhatian bahawa Incr GC adalah sangat tinggi. Ini bermakna V8 sedang berusaha keras untuk mengosongkan ingatan.

memwatch.on('leak', ...): Aliran peruntukan timbunan

Kami telah menentukan algoritma pengesanan mudah untuk memaklumkan anda bahawa aplikasi anda mungkin mengalami kebocoran memori. Iaitu, jika selepas lima GC berturut-turut, memori masih diperuntukkan tetapi tidak dikeluarkan, nod-memwatch akan mengeluarkan peristiwa kebocoran. Format maklumat khusus acara itu jelas dan mudah dibaca, seperti ini:

{ start: Fri, 29 Jun 2012 14:12:13 GMT,
 end: Fri, 29 Jun 2012 14:12:33 GMT,
 growth: 67984,
 reason: 'heap growth over 5 consecutive GCs (20s) - 11.67 mb/hr' }
Salin selepas log masuk

memwatch.HeapDiff(): 查找泄漏元凶

最后,node-memwatch能比较堆上对象的名称和分配数量的快照,其对比前后的差异可以帮助找出导致内存泄漏的元凶。

var hd = new memwatch.HeapDiff();
 
// Your code here ...
 
var diff = hd.end();
Salin selepas log masuk

对比产生的内容就像这样:

{
 "before": {
  "nodes": 11625,
  "size_bytes": 1869904,
  "size": "1.78 mb"
 },
 "after": {
  "nodes": 21435,
  "size_bytes": 2119136,
  "size": "2.02 mb"
 },
 "change": {
  "size_bytes": 249232,
  "size": "243.39 kb",
  "freed_nodes": 197,
  "allocated_nodes": 10007,
  "details": [
   {
    "what": "Array",
    "size_bytes": 66688,
    "size": "65.13 kb",
    "+": 4,
    "-": 78
   },
   {
    "what": "Code",
    "size_bytes": -55296,
    "size": "-54 kb",
    "+": 1,
    "-": 57
   },
   {
    "what": "LeakingClass",
    "size_bytes": 239952,
    "size": "234.33 kb",
    "+": 9998,
    "-": 0
   },
   {
    "what": "String",
    "size_bytes": -2120,
    "size": "-2.07 kb",
    "+": 3,
    "-": 62
   }
  ]
 }
}
Salin selepas log masuk

HeapDiff方法在进行数据采样前会先进行一次完整的垃圾回收,以使得到的数据不会充满太多无用的信息。memwatch的事件处理会忽略掉由HeapDiff触发的垃圾回收事件,所以在stats事件的监听回调函数中你可以安全地调用HeapDiff方法。

Label berkaitan:
sumber:php.cn
Kenyataan Laman Web ini
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
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!