mysql 变量生命周期_Go: 延长变量的生命周期

![Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/00.png)

本文基于 Go 1.13。

在 Go 中,我们不需要自己管理内存分配和释放。然而,有些时候我们需要对程序进行更细粒度的控制。Go 运行时提供了很多种控制运行时状态及其与内存管理器之间相互影响的方式。本文中,我们来审查让变量不被 GC 回收的能力。

## 场景

我们来看一个基于 [Go 官方文档](https://golang.org/pkg/runtime/#KeepAlive) 的例子:

```go

type File struct { d int }

func main() {

p := openFile("t.txt")

content := readFile(p.d)

println("Here is the content: "+content)

}

func openFile(path string) *File {

d, err := syscall.Open(path, syscall.O_RDONLY, 0)

if err != nil {

panic(err)

}

p := &File{d}

runtime.SetFinalizer(p, func(p *File) {

syscall.Close(p.d)

})

return p

}

func readFile(descriptor int) string {

doSomeAllocation()

var buf [1000]byte

_, err := syscall.Read(descriptor, buf[:])

if err != nil {

panic(err)

}

return string(buf[:])

}

func doSomeAllocation() {

var a *int

// memory increase to force the GC

for i:= 0; i < 10000000; i++ {

i := 1

a = &i

}

_ = a

}

```

[源码地址](https://gist.githubusercontent.com/blanchonvincent/a247b6c2af559b62f93377b5d7581b7f/raw/6488ec2a36c28c46f942b7ac8f24af4e75c19a2f/main.go)

这个程序中一个函数打开文件,另一个函数读取文件。代表文件的结构体注册了一个 finalizer,在 gc 释放结构体时自动关闭文件。运行这个程序,会出现 panic:

```bash

panic: bad file descriptor

goroutine 1 [running]:

main.readFile(0x3, 0x5, 0xc000078008)

main.go:42 +0x103

main.main()

main.go:14 +0x4b

exit status 2

```

下面是流程图:

- 打开文件,返回一个文件描述符

- 这个文件描述符被传递给读取文件的函数

- 这个函数首先做一些繁重的工作:

![图 01](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/01.png)

allocate 函数触发 gc:

![02.png](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/02.png)

因为文件描述符是个整型,并以副本传递,所以打开文件的函数返回的结构体 `*File*` 不再被引用。Gc 把它标记为可以被回收的。之后触发这个变量注册的 finalizer,关闭文件。

然后,主协程读取文件:

![03.png](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/03.png)

因为文件已经被 finalizer 关闭,所以会出现 panic。

## 让变量不被回收

`runtime` 包暴露了一个方法,用来在 Go 程序中避免出现这种情况,并显式地声明了让变量不被回收。在运行到这个调用这个方法的地方之前,gc 不会清除指定的变量。下面是加了对这个方法的调用的新代码:

![04.png](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/04.png)

在运行到 `keepAlive` 方法之前,gc 不能回收变量 `p`。如果你再运行一次程序,它会正常读取文件并成功终止。

## 追本逐源

`keepAlive` 方法本身没有做什么:

![05.png](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/05.png)

运行时,Go 编译器会以很多种方式优化代码:函数内联,死码消除,等等。这个函数不会被内联,Go 编译器可以轻易地探测到哪里调用了 `keepAlive`。编译器很容易追踪到调用它的地方,它会发出一个特殊的 SSA 指令,以此来确保它不会被 gc 回收。

![06.png](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/06.png)

在生成的 SSA 代码中也可以看到这个 SSA 指令:

![07.png](https://raw.githubusercontent.com/studygolang/gctt-images2/master/20191002-Go-Keeping-a-Variable-Alive/07.png)

在我的文章 [Go 编译器概述](https://medium.com/a-journey-with-go/go-overview-of-the-compiler-4e5a153ca889) 中你可以看到更多关于 Go 编译器和 SSA 的信息。

本文由 GCTT 原创编译,Go语言中文网 荣誉推出

本文由 GCTT 原创翻译,Go语言中文网 首发。也想加入译者行列,为开源做一些自己的贡献么?欢迎加入 GCTT!

翻译工作和译文发表仅用于学习和交流目的,翻译工作遵照 CC-BY-NC-SA 协议规定,如果我们的工作有侵犯到您的权益,请及时联系我们。

欢迎遵照 CC-BY-NC-SA 协议规定 转载,敬请在正文中标注并保留原文/译文链接和作者/译者等信息。

文章仅代表作者的知识和看法,如有不同观点,请楼下排队吐槽

有疑问加站长微信联系(非本文作者))

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

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

相关文章

python qqbot实现qq聊天机器人_Python QQBot库的QQ聊天机器人

本文实例为大家分享了Python QQBot库的QQ聊天机器人的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下1.安装pip install qqbot2.主动发出消息from qqbot import _bot as bot# 登录QQbot.Login([-q, 2816626661])buddy 获取指定名称/备注的好友group 获取群buddy bot…

tp5 mysql实现消息队列_TP5系列 | Queue消息队列

消费信息如下ThinkPHP5 Queue消息队列优点1、Queue内置了 Redis&#xff0c;Database&#xff0c;Topthink &#xff0c;Sync这四种驱动&#xff0c;本文使用Redis驱动2、Queue消息队列适用于大并发或者返回结果 时间有点长并需要批量操作的第三方接口&#xff0c;可用于短信发…

mysql表里插不进去数据_Oracle数据中表值插不进去问题(转)

相信我们在进行测试的时候&#xff0c;有的时候会遇上数据库表的值插不进去的情况&#xff0c;在执行&#xff33;&#xff31;&#xff2c;语句的时候&#xff0c;好像卡住一样&#xff0c;没有反应。但是当你把&#xff33;&#xff31;&#xff2c;语句&#xff43;&#xf…

java 类默认访问权限_Java类 成员 访问权限 默认

Java中的访问权限控制符有四个.作用域 当前类 同一package 子孙类 其他packagepublic √ √ √ √protected √ …

java创建临时文件夹_java创建临时文件

[java]代码库/*** 创建临时文件** param prefix* 临时文件名的前缀* param suffix* 临时文件名的后缀* param dirName* 临时文件所在的目录&#xff0c;如果输入null&#xff0c;则在用户的文档目录下创建临时文件* return 临时文件创建成功返回true&#xff0c;否则返回false*…

java quartz2.1_quartz 2.1学习(一)

quartz是一种开源任务调度框架&#xff0c;提供了强大的任务调度机制&#xff0c;Quartz允许开发人员灵活地定义触发器的调度时间表&#xff0c;并可对触发器和任务进行关联映射。废话不多说了&#xff0c;介绍一下编程的基本步骤&#xff1a;实现Job接口&#xff0c;编码实现需…

java http setheader_response.setHeader各种用法详解

本文主要介绍了response.setHeader各种用法。具有很好的参考价值&#xff0c;下面跟着小编一起来看下吧一秒刷新页面一次 response.setHeader("refresh","1");二秒跳到其他页面 response.setHeader("refresh","2;URLotherPagename");没…

datagridview取消默认选中_C# WinForm 取消DataGridView的默认选中Cell 使其不反蓝

dataGridView1.Rows[0].Selected false;默认情况下 DataGridView绑定数据后会选中首行首列为实现其没有默认不选中(即绑定后 看不到首行首列反蓝)之前将dataGridView1.Rows[0].Selected false;放在窗体的构造函数中 怎么都看似不起效果 首行首列还是反蓝后来尝试放在窗体的Lo…

java多线程的优点_【java多线程的优点】

作者&#xff1a;Jakob Jenkov 翻译&#xff1a;古圣昌 校对&#xff1a;欧振聪尽管面临很多挑战&#xff0c;在java学习中多线程有一些优点使得它一直被使用。这些优点是&#xff1a;资源利用率更好程序设计在某些情况下更简单程序响应更快资源利用率更好想…

java boolean是什么_java中的boolean与Boolean有什么不同

java中的boolean与Boolean有什么不同发布时间&#xff1a;2020-11-11 15:59:21来源&#xff1a;亿速云阅读&#xff1a;74作者&#xff1a;Leah这篇文章给大家介绍java中的boolean与Boolean有什么不同&#xff0c;内容非常详细&#xff0c;感兴趣的小伙伴们可以参考借鉴&#x…

linux cmake编译安装mysql_Linux源码安装MySQL 5.6.12 (Cmake编译)

Linux源码安装MySQL 5.6.12 (Cmake编译)1.安装make编译器(默认系统自带)下载地址&#xff1a;tar zxvf make-3.82.tar.gzcd make-3.82./configuremakemake install2.安装bison下载地址&#xff1a;tar zxvf bison-2.5.tar.gzcd bison-2.5./configuremakemake install3.安装gcc-…

啊哈java_1.桶排序——啊哈算法java实现

/*** 题目&#xff1a;* 5个人考试得分分别为 5分&#xff0c;3分&#xff0c;5分&#xff0c;2分&#xff0c;8分;满分是10分;* 要将 5 3 5 2 8 这个数组进行降序排序;* 即排序后变为 8 5 5 3 2;* *//*** 桶排序解法&#xff1a; 建一个大小为11的一维数组a,a[0]~a[10]元素都初…

java成员变量的初始化_Java成员变量初始化过程

import java.util.*;public class Main{public static void main(String[] args){Student s new Student(5);s.show();}}class Person{public Person(){System.out.println("父初始化");show();}public void show(){System.out.println("父show");}}class…

java校招面试题_java校招面试编程题及答案.docx

java校招面试编程题及答案java校招面试编程题及答案  Java集合框架为Java编程语言的基础&#xff0c;也是Java面试中很重要的一个知识点。这里&#xff0c;我列出了一些关于Java集合的重要问题和答案。   集合框架是什么?说出一些集合框架的优点?   每种编程语言中都有…

合并两个有序数组 java_合并两个有序的数组

/*** 写在前面&#xff0c;题目要求的是将有序数组合并&#xff0c;那么有可能这所谓的有序是顺序或者逆序* 所以&#xff0c;应该在开始的时候判断一下* 然后&#xff0c;在比较的时候应该根据顺序逆序来写判断逻辑* 不过常规应该是顺序递增&#xff0c;然后就有了以下的代码&…

arp linux 清空_Linux怎么清理ARP缓存

1、系统初始arp环境[rootesx ~]# arp -nAddress HWtype HWaddress Flags Mask Iface192.168.1.175 ether 00:24:1D:97:B6:7F C vswif0192.168.1.120 ether 00:1F:C6:3A:DC:81 C vswif0192.168.1.51 (incomplete) vswif02、执行清除所有arp 缓存命令[rootesx ~]# arp -n|awk /^[…

ctf mysql hash传递_分享个 CTF 小工具 bruteHASH

别问&#xff0c;问就是为了 CTF思路源于一次三小时十二题的内部 CTF 竞赛&#xff0c;其中一道简单 MISC 给出明文范围(字母数字)和 MD5 开头&#xff0c;要求穷举出 flag——这当然不难&#xff0c;python 十几行代码搞定&#xff0c;但是运行出结果竟然用了近 20 分钟&#…

JAVA怎么实现网页退出系统_java后台实现js关闭本页面,父页面指定跳转或刷新操作...

关闭本页面&#xff0c;跳转到百度response.setCharacterEncoding("gbk");PrintWriter outresponse.getWriter();out.print("");out.print("");关闭本页面&#xff0c;刷新父页面response.setCharacterEncoding("gbk");PrintWriter ou…

huffman树java_HuffmanTree - java实现

该思想借鉴于《2019版数据结构高分笔记(c语言版)》- 第7版最近事多&#xff0c;有时间会把思路在这里阐述一下代码思路如下/*** add() 输入names[] weights[]* sort()排序* generateTree()生成树* preOrder() 先序遍历生成节点编码code* inOrder() 前序遍历输出编码** root* / …

java crontriggerbean_java – 使用JobStoreTX为石英聚类配置CronTriggerFactoryBean

我们正在使用Quartz 2.1.5;我们设置了以下属性&#xff1a;org.quartz.jobStore.classorg.quartz.impl.jdbcjobstore.JobStoreTXorg.quartz.jobStore.driverDelegateClassorg.quartz.impl.jdbcjobstore.CloudscapeDelegateorg.quartz.jobStore.useProperties trueorg.quartz.j…