递归将字符串添加到切片中会导致golang内存不足错误

时间:2019-12-06 15:14:54

标签: go out-of-memory slice

我正在尝试解析HTML页面并打印其链接。 我正在遍历解析的HTML树,以递归方式将链接添加到一片字符串中。 我遇到内存不足错误

时,缺少了一些东西

这是我的代码:

package parser

import (
    "errors"
    "io"

    "golang.org/x/net/html"
)

//URLParser returns all the urls inside a html page
type URLParser struct {
}

//GetURLS returns all
func (URLParser) GetURLS(htmlInput io.Reader) (*[]string, error) {

    result := []string{}
    htmlRoot, err := html.Parse(htmlInput)
    //result := make([]string, 1000)

    if err != nil {
        parserError := errors.New("html parser failed with error" + err.Error())
        return nil, parserError
    }

    finalResult := traverseHTMLTree(htmlRoot, &result)
    return finalResult, nil
}

func traverseHTMLTree(node *html.Node, result *[]string) *[]string {

    if node == nil {
        return nil
    }
    if isLinkElement(node) {
        currlink, shouldUse := getURLAttrb(node.Attr)
        if shouldUse {

            *result = append(*result, currlink)
        }

    }

    for currNode := node.FirstChild; currNode != nil; currNode = currNode.NextSibling {
        currRest := traverseHTMLTree(currNode, result)
        if currRest != nil {
            *result = append(*currRest, *result...)
        }
    }
    return result
}

func getURLAttrb(attr []html.Attribute) (string, bool) {
    for i := 0; i < len(attr); i++ {
        if attr[i].Key == "href" {
            return attr[i].Val, true
        }
    }
    return "", false
}

func isLinkElement(node *html.Node) bool {
    if node.Type == html.ElementNode {
        if node.Data == "a" {
            return true
        }
    }
    return false
}

当仅尝试打印指向stdout的链接时,它可以完美地工作,因此它必须与我处理切片的方式有关。

1 个答案:

答案 0 :(得分:1)

对于HTML树中的每个节点,您将递归将结果数组的内容添加到其自身。那应该增长很快。

请注意,当您检查isLinkElement是否将项目添加到结果列表中时。

然后,对于html树的每个元素,将结果数组的内容附加到其自身,使其成倍增加。

您正在将指针传递给切片。您实际上在整个程序中使用了一个切片,并不断添加其中。您从traverseHTMLTree返回的内容是同一切片,而不是其副本。因此它一直在增长。

一种解决方法:不要将指针传递给切片。传递当前切片,对其进行更新,然后返回新切片。

相关问题