首页 > 后端开发 > Golang > html 渲染函数内存泄漏

html 渲染函数内存泄漏

王林
发布: 2024-02-06 10:39:11
转载
783 人浏览过

html 渲染函数内存泄漏

问题内容

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

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 方法导致大量内存使用。bytes.buffersync.pool 但两者都有相同的问题。使用 pprof 我注意到 strings.builder 的 writestring 方法导致大量内存使用。


正确答案


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

正确答案

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

url发送

任何不代表html数据的内容application/pdf ,然后正文将包含 html.Parse仍然接受它而不抛出错误。

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

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

以上是html 渲染函数内存泄漏的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板