Speicherverlust der HTML-Rendering-Funktion

王林
Freigeben: 2024-02-06 10:39:11
nach vorne
642 Leute haben es durchsucht

html 渲染函数内存泄漏

Frageninhalt

Das Problem, mit dem ich konfrontiert bin, besteht darin, dass selbst der Versuch von nur 200 Anfragen dazu führt, dass das Programm 6 GB des Speichers des Containers belegt und schließlich von oom beendet wird. Meine Idee ist, alle im HTML vorhandenen Textknoten zu extrahieren und sie dann zu verarbeiten, um ihren Namen, den HTML-Code und den Text dieses Tags zu extrahieren. Um also HTML für ein bestimmtes Tag zu generieren, verwende ich die Renderfunktion von golang.org/x/net/html. Wo ich strings.builder als io.writer bereitstelle, um den generierten HTML-Code zu schreiben. Aber aus irgendeinem Grund beansprucht der Builder zu viel Speicher.

package main

import (
    "encoding/csv"
    "io"
    "log"
    "net/http"
    "strings"
    "golang.org/x/net/html"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/data", GetData)
    if err := http.ListenAndServe(":8001", mux); err != nil {
        log.Println(err)
    }
}

type TagInfo struct {
    Tag  string
    Name string
    Text string
}

// http.handler
func GetData(w http.ResponseWriter, r *http.Request) {
    u := r.URL.Query().Get("url")
    doc, err := GetDoc(u)
    if err != nil {
        log.Println(err)
        w.WriteHeader(500)
        return
    }
    var buf strings.Builder
    data := Extract(doc, &buf)
    csvw := csv.NewWriter(io.Discard)
    for _, d := range data {
        csvw.Write([]string{d.Name, d.Tag, d.Text})
    }
}

// fires request and get text/html
func GetDoc(u string) (*html.Node, error) {
    res, err := http.Get(u)
    if err != nil {
        return nil, err
    }
    defer res.Body.Close()
    return html.Parse(res.Body)
}

func Extract(doc *html.Node, buf *strings.Builder) []TagInfo {
    var (
        tags = make([]TagInfo, 0, 100)
        f    func(*html.Node)
    )

    f = func(n *html.Node) {
        if n.Type == html.TextNode {
            text := strings.TrimSpace(n.Data)
            if text != "" {
                parent := n.Parent
                tag := Render(parent, buf)
                tagInfo := TagInfo{
                    Tag:  tag,
                    Name: parent.Data,
                    Text: n.Data,
                }
                tags = append(tags, tagInfo)
            }
        }
        for child := n.FirstChild; child != nil; child = child.NextSibling {
            f(child)
        }
    }
    f(doc)
    return tags
}

// Render the html around the tag
// if node is text then pass the
// parent node paramter in function
func Render(n *html.Node, buf *strings.Builder) string {
    defer buf.Reset()
    if err := html.Render(buf, n); err != nil {
        log.Println(err)
        return ""
    }
    return buf.String()
}
Nach dem Login kopieren

Wenn Sie eine bestimmte Liste von URLs wünschen, finden Sie sie hier. Ich habe ungefähr 60 Anfragen gleichzeitig gestellt.

Ich habe versucht, bytes.buffer bytes.buffer und sync.pool zu verwenden, aber beide haben das gleiche Problem. Bei der Verwendung von pprof ist mir aufgefallen, dass die writestring-Methode von strings.builder viel Speicher verbraucht. <code>bytes.buffersync.pool 但两者都有相同的问题。使用 pprof 我注意到 strings.builder 的 writestring 方法导致大量内存使用。


正确答案


所以这里的基本问题是接受任何 content-type ,这在抓取方面是不可接受的,大多数网站都需要发送 text/html

Richtige Antwort

Das Grundproblem hier besteht also darin, jeden Inhaltstyp zu akzeptieren, der im Hinblick auf das Crawlen nicht akzeptabel ist, was die meisten Websites benötigen um text/html zu senden. golang.org/x/net/htmlDas Problem besteht darin, dass die

URL, selbst wenn sie

alles sendet, was keine HTML-Daten darstellt application/pdf ,然后正文将包含 html.Parse, diese dennoch akzeptiert, ohne einen Fehler auszulösen.

Nehmen wir ein Beispiel, bei dem die Binärdaten der analysierten PDF-Datei zurückgegeben werden und kein Fehler zurückgegeben wird. Dies ist eine seltsame Verhaltensgedankenbibliothek zum Scrapen/Crawlen, die Binärdaten akzeptiert.

🎜Die Lösung lautet: 🎜Überprüfen Sie die Antwortheader. Wenn nur die Daten HTML sind, fahren Sie fort, andernfalls kommt es zu Mehrdeutigkeiten oder einer höheren Speichernutzung (möglicherweise weniger), aber wir können nicht vorhersagen, was passieren wird. 🎜

Das obige ist der detaillierte Inhalt vonSpeicherverlust der HTML-Rendering-Funktion. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:stackoverflow.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!