文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

html 渲染函数内存泄漏

2024-02-06 10:31

关注

问题内容

我面临的问题是,即使仅尝试 200 个请求也会导致程序占用容器的 6gb 内存并最终被 oom 杀死。 我的想法是提取 html 中存在的所有文本节点,然后处理它们以提取它们的名称、该标签的 html 和文本。因此,为了生成特定标签的 html,我使用 golang.org/x/net/html 中的 render 函数。其中我提供 strings.builder 作为 io.writer 来编写生成的 html。但由于某种原因,构建器占用了太多内存。

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

如果您想要特定的网址列表,这里就是。我一次发出了大约 60 个请求。

我尝试使用 bytes.buffer bytes.buffersync.pool 但两者都有相同的问题。使用 pprof 我注意到 strings.builder 的 writestring 方法导致大量内存使用。


正确答案


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

问题是即使url发送任何不代表html数据的内容golang.org/x/net/html仍然接受它而不抛出错误。

让我们举一个例子,其中返回 application/pdf ,然后正文将包含 html.Parse 解析的 pdf 的二进制数据,并且不会返回任何错误,这是用于抓取/爬行接受二进制数据的奇怪行为思维库。

解决方案是:检查响应头,如果只有数据是html,然后继续,否则会出现歧义或更高的内存使用量(可能更低),但我们无法预测会发生什么发生。

以上就是html 渲染函数内存泄漏的详细内容,更多请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 资料下载
  • 历年真题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯