Goland 内存逃逸问题

内存逃逸是什么?

在go语言中,内存分配存在两个方式:堆分配;栈分配。

栈分配:是在函数调用时为局部变量分配内存,当函数返回时,这些内存会自动释放。

堆分配:通过 new 或者 make 函数动态分配内存,需要手动进行释放或者自动回收机制释放。

内存逃逸是指原先在栈上分配的内存被分配到堆上。这样导致函数结束时不能自动回收,只能通过垃圾回收器回收,对于性能影响较大。

内存逃逸的几种情况

1.返回指针导致内存逃逸

package mainimport "fmt"func createPointer() *int {x := 100 // 局部变量return &x // x 逃逸到堆上
}func main() {p := createPointer()fmt.Println(*p) // 100
}

为什么发生了逃逸?

  • xcreatePointer() 的局部变量,正常情况下函数返回后应该销毁
  • 但是 &x 返回了 x 的地址,导致 x 需要在 main() 继续使用,不能放在栈上,必须逃逸到堆

2.切片或 map 赋值导致逃逸

package mainfunc main() {s := make([]int, 3) // 堆分配m := make(map[int]int) // 堆分配_ = s_ = m
}

为什么发生了逃逸?

  • make([]int, 3) 创建了切片,其底层数组可能存储在堆上(具体取决于大小)
  • make(map[int]int) 创建的 map 结构存储在堆上,因为 map 需要在多个作用域间传递。

3.字符串和 interface{} 赋值导致逃逸

package mainimport "fmt"func printAny(i interface{}) {fmt.Println(i)
}func main() {x := "hello"printAny(x) // x 逃逸到堆
}

为什么发生了逃逸?

  • xstring,但 printAny() 需要 interface{}
  • Go 需要将 x 装箱(boxing),创建 interface{} 类型的值,而 interface{} 可能存储在堆上

4.闭包捕获变量导致逃逸

package mainimport "fmt"func closure() func() int {x := 42return func() int {return x // x 逃逸到堆}
}func main() {f := closure()fmt.Println(f()) // 42
}

为什么发生了逃逸?

  • xclosure() 的局部变量,但被匿名函数 func() int 捕获
  • 由于 func() int 可能在 closure() 结束后仍然被调用,x 必须分配到堆上

如何避免内存逃逸?

避免返回指针

错误情况

// ❌ 发生逃逸
func bad() *int {
    x := 42
    return &x
}

改进(使用值返回,而不是指针) 

func good() int {
    x := 42
    return x // 不逃逸
}

使用参数传递而不是使用闭包

func returnFunction(x int) func() int {
    return func() int { return x }
}

 使用 sync.Pool 复用对象

package main

import (
    "fmt"
    "sync"
)

var pool = sync.Pool{
    New: func() interface{} { return new(int) },
}

func main() {
    p := pool.Get().(*int) // 复用对象,减少堆分配
    *p = 100
    fmt.Println(*p)
    pool.Put(p) // 归还对象
}

 使用 strings.Builder 代替字符串拼接

package main

import (
    "fmt"
    "strings"
)

func main() {
    var sb strings.Builder // 避免字符串逃逸
    sb.WriteString("Hello ")
    sb.WriteString("World")
    fmt.Println(sb.String())
}

总结

逃逸原因例子解决方案
返回指针return &x返回值而不是指针
切片/Mapmake([]int, 3)小数组可用 var arr [3]int
interface{}printAny(x)避免不必要的 interface{}
闭包捕获变量return func() { return x }使用 参数传递 而不是 闭包
字符串拼接s += "hello"strings.Builder

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/15159.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Matlab优化算法-第14期】基于智能优化算法的VMD信号去噪项目实践

基于智能优化算法的VMD信号去噪项目实践 一、前言 在信号处理领域,噪声去除是一个关键问题,尤其是在处理含有高斯白噪声的复杂信号时。变分模态分解(VMD)作为一种新兴的信号分解方法,因其能够自适应地分解信号而受到…

C++ 继承(1)

1.继承概念 我们平时有时候在写多个有内容重复的类的时候会很麻烦 比如我要写Student Teacher Staff 这三个类 里面都要包含 sex name age成员变量 唯一不同的可能有一个成员变量 但是这三个成员变量我要写三遍 太麻烦了 有没有好的方式呢? 有的 就是继承…

生成式聊天机器人 -- 基于Pytorch + Global Attention + 双向 GRU 实现的SeqToSeq模型 -- 下

生成式聊天机器人 -- 基于Pytorch Global Attention 双向 GRU 实现的SeqToSeq模型 -- 下 训练Masked 损失单次训练过程迭代训练过程 测试贪心解码(Greedy decoding)算法实现对话函数 训练和测试模型完整代码 生成式聊天机器人 – 基于Pytorch Global Attention 双向 GRU 实…

《ARM64体系结构编程与实践》学习笔记(四)

MMU内存管理 1.MMU内存管理(armv8.6手册的D5章节),MMU包含快表TLB,TLB是对页表的部分缓存,页表是存放在内存里面的。 AArch64仅仅支持Long Descriptor的页表格式,AArch32支持两种页表格式Armv7-A Short De…

如何在Vscode中接入Deepseek

一、获取Deepseek APIKEY 首先,登录Deepseek官网的开放平台:DeepSeek 选择API开放平台,然后登录Deepseek后台。 点击左侧菜单栏“API keys”,并创建API key。 需要注意的是,生成API key复制保存到本地,丢失…

Docker 部署 MinIO | 国内阿里镜像

一、导读 Minio 是个基于 Golang 编写的开源对象存储套件,基于Apache License v2.0开源协议,虽然轻量,却拥有着不错的性能。它兼容亚马逊S3云存储服务接口。可以很简单的和其他应用结合使用,例如 NodeJS、Redis、MySQL等。 二、…

DeepSeek-R1 32B Windows+docker本地部署

最近国产大模型DeepSeek兴起,本地部署了一套deepseek同时集成Open WebUI界面,给大家出一期教程。 软件:Ollama、docker、Open WebUI 一、用Ollama下载模型 首先我们需要安装Ollama,它可以在本地运行和管理大模型。 到Ollama官网 https://ol…

TCP服务器与客户端搭建

一、思维导图 二、给代码添加链表 【server.c】 #include <stdio.h> #include <sys/socket.h> #include <sys/types.h> #include <fcntl.h> #include <arpa/inet.h> #include <unistd.h> #include <stdlib.h> #include <string.…

python爬虫--简单登录

1&#xff0c;使用flask框架搭建一个简易网站 后端代码app.py from flask import Flask, render_template, request, redirect, url_for, sessionapp Flask(__name__) app.secret_key 123456789 # 用于加密会话数据# 模拟用户数据库 users {user1: {password: password1}…

ESXi Host Client创建ubuntu虚拟机教程及NVIDIA显卡驱动安装

参考文章 VMware虚拟机显卡直通记录 AIGC 实战&#xff08;环境篇&#xff09; - EXSI 8.0 Debian安装RTX3060显卡驱动 重点介绍 client版本是7.0.3 注意&#xff1a;下图中不要选择BIOS 按照两个链接中的方法进行操作&#xff0c;以及本章节的上面几个图片的配置之后&a…

Maven入门核心知识点总结

Maven 1. POM&#xff08;Project Object Model&#xff09;2. 坐标&#xff08;Coordinates&#xff09;3. 依赖管理&#xff08;Dependency Management&#xff09;4. 常用五个生命周期&#xff08;Life Circle&#xff09;5. Maven 仓库&#xff08;Maven Repository&#x…

测试中的第一性原理:回归本质的质量思维革命

在软件工程领域&#xff0c;测试活动常被惯性思维和经验主义所主导——测试用例库无限膨胀、自动化脚本维护成本居高不下、测试策略与业务目标渐行渐远。要突破这种困境&#xff0c;第一性原理&#xff08;First Principles Thinking&#xff09;提供了独特的解题视角&#xff…

Rust语言进阶之标准输入: stdin用法实例(一百零五)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

SpringBoot速成(七)注册实战P2-P4

1.创建 数据库创建 依赖引入 <!-- mybatis起步依赖--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version></dependency> <…

Spring Boot接入Deep Seek的API

1&#xff0c;首先进入deepseek的官网&#xff1a;DeepSeek | 深度求索&#xff0c;单击右上角的API开放平台。 2&#xff0c;单击API keys&#xff0c;创建一个API&#xff0c;创建完成务必复制&#xff01;&#xff01;不然关掉之后会看不看api key&#xff01;&#xff01;&…

【C++学习篇】C++11第二期学习

目录 1. 可变参数模板 1.1 基本语法及原理 1.2 包扩展 1.3empalce系列接⼝ 2. lamba 2.1 lambda的语法表达式 2.2 捕捉列表 2.3 lamba的原理 1. 可变参数模板 1.1 基本语法及原理 1. C11⽀持可变参数模板&#xff0c;也就是说⽀持可变数量参数的函数模板和类模板&…

开放式TCP/IP通信

一、1200和1200之间的开放式TCP/IP通讯 第一步&#xff1a;组态1214CPU&#xff0c;勾选时钟存储器 第二步&#xff1a;防护与安全里面连接机制勾选允许PUT/GET访问 第三步&#xff1a;添加PLC 第四步&#xff1a;点击网络试图&#xff0c;选中网口&#xff0c;把两个PLC连接起…

迁移学习 Transfer Learning

迁移学习&#xff08;Transfer Learning&#xff09;是什么&#xff1f; 迁移学习是一种机器学习方法&#xff0c;它的核心思想是利用已有模型的知识来帮助新的任务或数据集进行学习&#xff0c;从而减少训练数据的需求、加快训练速度&#xff0c;并提升模型性能。 &#x1f…

爬虫技巧汇总

一、UA大列表 USER_AGENT_LIST 是一个包含多个用户代理字符串的列表&#xff0c;用于模拟不同浏览器和设备的请求。以下是一些常见的用户代理字符串&#xff1a; USER_AGENT_LIST [Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; Hot Lingo 2.0),Mozilla…

我们来学人工智能 -- 将Ollama已下载的模型从C盘迁出

题记 未配置OLLAMA_MODELS系统变量导致模型下载到了C盘 迁移步骤 退出ollama 配置OLLAMA_MODELS系统变量 OLLAMA_MODELS&#xff1a;D:\ollama\models 直接将C盘下的models目录剪切到指定目录 检查 cmd命令窗口退出重新打开