2016-07-05 9 views
1

Ich habe einen sehr einfachen Crawler, es geht 250 Seiten durch, teilt ungefähr 400mb Speicher zu und befreit es nie. Ich habe keine Ahnung, wie ich das beheben soll, vielleicht bemerkt jemand etwas und lässt mich freundlich wissen.nodejs Speicherverlust (async.queue und Anfrage)

function scrape(shop, o, cb, step) { 

    var itemz = [] 

    var q = async.queue(function (o, cb) { 
     req({ 
      url: o.url 
     }, function (e, r) { 
      if (e) throw (e) 
      cb() 
      o.cb(r.body) 
     }) 
    }, o.threads) 
    var get = function (url, cb) { 
     q.push({ 
      url: url, 
      cb: cb 
     }) 
    } 

    var url = 'https://www.host.com' 
    var total, done = 0, 
     itemsPerPage = 24 

    get(url, function (r) { 

     pages = (r.match(/data-page="(\d+)"/g)); 
     pages = pages[pages.length - 2].split("data-page=\"")[1].split('"')[0] || 1; 
     pages = Math.min(pages, 10) // limit to 10 pages max (240 items) 

     for (var i = 1; i <= pages; i++) { 
      get(url + '&page=' + i, scrapeList) 
     } 
     total = pages + pages * itemsPerPage 
    }) 

    // - extract the transaction links from the pages: 
    // and add them to queue 
    function scrapeList(r) { 
     var itemsFound = 0 

     r.replace(/href="(https:\/\/www.host.com\/listing\/(\d+).*)"/g, function (s, itemUrl, dateSold) { 
      itemsFound++ 
      get(itemUrl, function (r) { 
       scrapeItem(r, itemUrl, dateSold) 
       step(++done, total) 
       if (done == total) onend() 
      }) 
     }) 

     total -= itemsPerPage - itemsFound // decrease expected items, if less items per page found than initially expected 
     step(++done, total) 
    } 

    // - from item page extract the details, and add to items array 
    function scrapeItem(r, itemUrl, dateSold) { 

     var d = {} 
     d.url = itemUrl; 

     d.date = new Date(Date.now()) 

     d.quantity = 1; 

     itemz.push(d) 
    } 

    // - when no more requests in a queue (on drain), group items by title 
    function onend() { 

     cb(null, itemz); 

    } 
} 
+0

Wie Sie die 'schaben anrufen (...)' Funktion? Es gibt ein Array für seinen Rückruf zurück. Wenn Sie dieses Array persistent speichern, wäre dies eine Menge persistenter Daten. – jfriend00

+0

Ich speichere es in Array und setInterval durchläuft das Array jede Minute und reinigt es (Cache löschen [k]); – freddor

+0

Haben Sie Heap-Snapshots ausgeführt und untersucht, was sich im Heap aufbaut? – jfriend00

Antwort

1

Ich hatte ein ähnliches Problem, wo ich einen Host abgekratzt und verwendet cheerio die HTML zu analysieren, aber Cheerio mit lodash intern hatte Speicherlecks, dass es nie veröffentlicht, so fand ich eine Arbeit um GC (Garbage Collector des Auslösens) in regelmäßigen Abständen um Speicher freizugeben, rufen Sie einfach global.gc(); nach reqular Intervallen, während das Skript mit Flagge --expose-gc

läuft zB: node <script>.js --expose-gc.

Dies ist keine ideale Lösung, aber es ist eine schnelle Lösung für den Standalone-Skript wie das Ihre siehe here, halte das Intervall auch nicht zu kurz, da ich bemerkt habe, dass die Speicherbereinigung CPU-intensiv ist und auch die Ereignisschleife verzögert, sodass alle 5 bis 10 Sekunden ausreichen sollten.

Auch fand ich eine interessante Lektüre über v8 Garbage Collection here

+0

Interessant, ich dachte immer, dass, wenn Speicher durch Garbage Collection (gezwungen oder nicht) freigegeben werden kann, es nicht leckt. – robertklep

+0

@robertklep nach dem Profilieren meiner Anwendung fand ich heraus, dass Cheerio riesige Arrays und Objekte aufgrund der Verwendung von loadash hatte. – AJS

+0

@robertklep Wenn Sie interessiert sind, sehen Sie den 2. Link in meiner Antwort, es gibt eine Erläuterung, wie v8 Garbage Collection funktioniert. – AJS