ホームページ  >  記事  >  バックエンド開発  >  データ構造でのメモリ リークを回避しながら、メモリ効率を高めるために Go でポインタを効果的に使用するにはどうすればよいでしょうか?

データ構造でのメモリ リークを回避しながら、メモリ効率を高めるために Go でポインタを効果的に使用するにはどうすればよいでしょうか?

Patricia Arquette
Patricia Arquetteオリジナル
2024-10-28 10:02:02983ブラウズ

How to effectively use pointers in Go for memory efficiency while avoiding memory leaks in data structures?

Go におけるガベージ コレクションとポインターの正しい使用法

ポインターの背景

Go では、ポインターはメモリに格納されたデータをコピーせずに参照するために使用されます。データ自体。これにより、特に大規模または複雑なデータ構造を扱う場合に、パフォーマンスとメモリ効率が向上します。

問題

提供されたコードは、タグを画像 URL のリストにマップするデータ構造を作成することを目的としています。 。ただし、初期設計ではメモリを節約するためにポインタを使用することが検討されていたため、割り当てられたメモリの最終的なクリーンアップについて疑問が生じます。

質問への回答

バージョン 1:

  • URL フィールドへのポインタを使用すると、基になる文字列データがポインタによって引き続き参照されるため、メモリ リークが発生します。
  • 完全なイメージ構造体とそのすべてのフィールドは、メモリ内に残ります。 tagToUrlMap に格納されているポインターのいずれかがそれらを指しているためです。

バージョン 2:

  • URL 文字列を保持する中間変数を作成し、それへのポインタを使用すると、バージョン 1 によって引き起こされたメモリ リークの問題が解決されます。
  • ただし、間接的な処理と複雑さが追加され、メモリは大幅に節約されません。

最適な解決策

URL を保存する最も効率的な方法は、ポインターを使用せずに文字列値を直接使用することです。 Go は、文字列プール を使用して文字列を保存することで、すでに文字列処理を最適化しています。これにより、同じ文字列への複数の参照が単一のメモリ割り当てを共有できるようになります。

メモリ節約のための文字列インターニング

さらにメモリを節約するために、コードでは文字列インターニングを採用できます。これには、文字列のインスタンスを 1 つだけ保存し、同じ文字列が出現するたびにそのインスタンスを参照することが含まれます。

提供されたコードには、キャッシュを使用して以前に出現した文字列を保存および再利用する単純な文字列インターニング関数 (interned()) が含まれています。 .

修正されたコード

<code class="go">package main

import (
    "bytes"
    "encoding/json"
    "fmt"
)

type Image struct {
    URL string
    Description string
    Tags []Tag
}

type Tag struct {
    Name string
    Rank int
}

func searchImages() []*Image {
    parsedJSON := []*Image{
        &Image{
            URL: "https://c8.staticflickr.com/4/3707/11603200203_87810ddb43_o.jpg",
            Description: "Ocean islands",
            Tags: []Tag{
                Tag{"ocean", 1},
                Tag{"water", 2},
                Tag{"blue", 3},
                Tag{"forest", 4},
            },
        },
        &Image{
            URL: "https://c3.staticflickr.com/1/48/164626048_edeca27ed7_o.jpg",
            Description: "Bridge over river",
            Tags: []Tag{
                Tag{"bridge", 1},
                Tag{"river", 2},
                Tag{"water", 3},
                Tag{"forest", 4},
            },
        },
    }
    return parsedJSON
}

func interned(s string) string {
    if str, ok := cache[s]; ok {
        return str
    }
    cache[s] = s
    return s
}

var cache = make(map[string]string)

func main() {
    result := searchImages()

    tagToUrlMap := make(map[string][]string)

    for _, image := range result {
        imageURL := interned(image.URL)

        for _, tag := range image.Tags {
            tagName := interned(tag.Name)
            tagToUrlMap[tagName] = append(tagToUrlMap[tagName], imageURL)
        }
    }

    // Clear the interner cache
    cache = nil

    // Trim allocated slices to the minimum needed
    for tagName, urls := range tagToUrlMap {
        if cap(urls) > len(urls) {
            urls2 := make([]string, len(urls))
            copy(urls2, urls)
            tagToUrlMap[tagName] = urls2
        }
    }

    enc := json.NewEncoder(os.Stdout)
    enc.SetIndent("", "  ")
    if err := enc.Encode(tagToUrlMap); err != nil {
        panic(err)
    }
}</code>

追加リソース

  • [同時実行は並列処理ではありません](https://blog.golang.org/go-nuts)
  • [Go のメモリ管理について](https://blog.gopheracademy.com/advent-2016/ Understanding-memory-management-in-go/)
  • [Go のガベージ コレクション] ](https://www.golang-book.com/books/intro/12)
  • [stringsx.Pool](https://github.com/icza/gox) (文字列プール)

以上がデータ構造でのメモリ リークを回避しながら、メモリ効率を高めるために Go でポインタを効果的に使用するにはどうすればよいでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。