一、内存泄漏

内存泄露,是从操作系统的角度上来阐述的,形象的比喻就是“操作系统可提供给所有进程的存储空间(虚拟内存空间)正在被某个进程榨干”,导致的原因就是程序在运行的时候,会不断地动态开辟的存储空间,这些存储空间在在运行结束之后后并没有被及时释放掉。应用程序在分配了某段内存之后,由于设计的错误,会导致程序失去了对该段内存的控制,造成了内存空间的浪费。

如果程序在内存空间内申请了一块内存,之后程序运行结束之后,没有把这块内存空间释放掉,而且对应的程序又没有很好的gc机制去对程序申请的空间进行回收,这样就会导致内存泄露。

二、GC原理

root

首先标记root根对象,根对象的子对象也是存活的。

根对象包括:全局变量,各个G stack上的变量等。

标记

span是内存管理的最小单位,所以猜测gc的粒度也是span。

如图所示,通过gcmarkBits位图标记span的块是否被引用。对应内存分配中的bitmap区。

三色标记

  • 灰色:对象已被标记,但这个对象包含的子对象未标记
  • 黑色:对象已被标记,且这个对象包含的子对象也已标记,gcmarkBits对应的位为1(该对象不会在本次GC中被清理)
  • 白色:对象未被标记,gcmarkBits对应的位为0(该对象将会在本次GC中被清理)

例如,当前内存中有A~F一共6个对象,根对象a,b本身为栈上分配的局部变量,根对象a、b分别引用了对象A、B, 而B对象又引用了对象D,则GC开始前各对象的状态如下图所示:

  1. 初始状态下所有对象都是白色的。
  2. 接着开始扫描根对象a、b; 由于根对象引用了对象A、B,那么A、B变为灰色对象,接下来就开始分析灰色对象,分析A时,A没有引用其他对象很快就转入黑色,B引用了D,则B转入黑色的同时还需要将D转为灰色,进行接下来的分析。
  3. 灰色对象只有D,由于D没有引用其他对象,所以D转入黑色。标记过程结束
  4. 最终,黑色的对象会被保留下来,白色对象会被回收掉。
 

STW

stop the world是gc的最大性能问题,对于gc而言,需要停止所有的内存变化,即停止所有的goroutine,等待gc结束之后才恢复。

触发

  • 阈值:默认内存扩大一倍,启动gc
  • 定期:默认2min触发一次gc,src/runtime/proc.go:forcegcperiod
  • 手动:runtime.gc()

三、GC过程

GO的GC是并行GC, 也就是GC的大部分处理和普通的go代码是同时运行的, 这让GO的GC流程比较复杂.

  1. Stack scan:Collect pointers from globals and goroutine stacks。收集根对象(全局变量,和G stack),开启写屏障。全局变量、开启写屏障需要STW,G stack只需要停止该G就好,时间比较少。
  2. Mark: Mark objects and follow pointers。标记所有根对象, 和根对象可以到达的所有对象不被回收。
  3. Mark Termination: Rescan globals/changed stack, finish mark。重新扫描全局变量,和上一轮改变的stack(写屏障),完成标记工作。这个过程需要STW。
  4. Sweep: 按标记结果清扫span

目前整个GC流程会进行两次STW(Stop The World), 第一次是Stack scan阶段, 第二次是Mark Termination阶段.

  • 第一次STW会准备根对象的扫描,启动写屏障(Write Barrier)和辅助GC(mutator assist).
  • 第二次STW会重新扫描部分根对象,禁用写屏障(Write Barrier)和辅助GC(mutator assist).

从1.8以后的golang将第一步的stop the world 也取消了,这又是一次优化; 1.9开始, 写屏障的实现使用了Hybrid Write Barrier, 大幅减少了第二次STW的时间.

写屏障

因为go支持并行GC, GC的扫描和go代码可以同时运行, 这样带来的问题是GC扫描的过程中go代码有可能改变了对象的依赖树。

例如开始扫描时发现根对象A和B, B拥有C的指针。

  1. GC先扫描A,A放入黑色
  2. B把C的指针交给A
  3. GC再扫描B,B放入黑色
  4. C在白色,会回收;但是A其实引用了C。

为了避免这个问题, go在GC的标记阶段会启用写屏障(Write Barrier).

启用了写屏障(Write Barrier)后,在GC第三轮rescan阶段,根据写屏障标记将C放入灰色,防止C丢失。

Golang GC原理的更多相关文章

  1. golang gc 问题(转的)

    在实际使用go语言的过程中,碰到了一些看似奇怪的内存占用现象,于是决定对go语言的垃圾回收模型进行一些研究.本文对研究的结果进行一下总结. 什么是垃圾回收? 曾几何时,内存管理是程序员开发应用的一大难 ...

  2. golang ----gc问题

    go程序内存占用大的问题 这个问题在我们对后台服务进行压力测试时发现,我们模拟大量的用户请求访问后台服务,这时各服务模块能观察到明显的内存占用上升.但是当停止压测时,内存占用并未发生明显的下降.花了很 ...

  3. Golang GC 垃圾回收机制详解

    摘要 在实际使用 go 语言的过程中,碰到了一些看似奇怪的内存占用现象,于是决定对go语言的垃圾回收模型进行一些研究.本文对研究的结果进行一下总结. 什么是垃圾回收? 曾几何时,内存管理是程序员开发应 ...

  4. 【转】Java 内存模型及GC原理

    一个优秀Java程序员,必须了解Java内存模型.GC工作原理,以及如何优化GC的性能.与GC进行有限的交互,有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率,才能 ...

  5. JVM初探- 内存分配、GC原理与垃圾收集器

    JVM初探- 内存分配.GC原理与垃圾收集器 标签 : JVM JVM内存的分配与回收大致可分为如下4个步骤: 何时分配 -> 怎样分配 -> 何时回收 -> 怎样回收. 除了在概念 ...

  6. Java 内存模型、GC原理及算法

    Java 内存模型.GC原理:https://blog.csdn.net/ithomer/article/details/6252552 GC算法:https://www.cnblogs.com/sm ...

  7. Java 内存模型及GC原理 (转载)

    一个优秀Java程序员,必须了解Java内存模型.GC工作原理,以及如何优化GC的性能.与GC进行有限的交互,有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率,才能 ...

  8. JVM相关文章和GC原理算法

    参考推荐: Java内存模型及GC原理 一个优秀的Java程序员必须了解的GC机制 Android 智能指针原理(推荐) Java虚拟机规范 Java虚拟机参数 Java内存模型 Java系列教程(推 ...

  9. golang GC(一 原理)

    golang中的gc采用三色标记法.在讲三色标记法之前,先了解一下Mark and Sweep算法,因为Mark and Sweep算法是三个标记法的一个改进版. Mark and Sweep算法: ...

随机推荐

  1. Django之Form、ModelForm 组件

    Django之Form.ModelForm 组件 一.Form组件: django框架提供了一个form类,来处理web开发中的表单相关事项.众所周知,form最常做的是对用户输入的内容进行验证,为此 ...

  2. Python3实战系列之五(获取印度售后数据项目)

    问题:续接上一篇.说干咱就干呀,勤勤恳恳写程序呀! 目标:此篇我们试着把python程序打包成.exe程序.这样就可以在服务器上运行了.实现首篇计划列表功能模块的第二步: 2.将python程序转为 ...

  3. python+selenium—webdriver入门(二)

    本文中主要介绍webdriver常见的对象定位方法: 一.对象定位的目的 二.常见的对象定位方法 一.对象定位的目的: 1.操作对象 2.获得对象的属性,如:对象的class属性.name属性等 3. ...

  4. HTML语言

    复习: 1.Web项目的部署结构  静态Web技术(客户端技术):提供的内容任何人在任何时间访问都是一样的 HTML/CSS/JS/Flash.... 动态Web技术(服务器端技术):提供的内容不同人 ...

  5. Python select模块学习

    select 是常用的异步socket 处理方法 一般用法: # iwtd,owtd,ewtd 分别为需要异步处理的读socket队列, 写socket队列(一般不用), 和错误socket队列, 返 ...

  6. pip更换国内源

    学习Python开发,据说pip是很好用的一个Python包管理工具,于是尝试使用,但源异常慢,于是切换至国内的源(清华源). 在~/.pip/pip.conf (如果没有此文件则自行新建) 内容 [ ...

  7. 将JSON数据转换成JAVA的实体类

    思路:首先将JSON格式的数据转换成JSONObject,然后将JSONObject转换成Java的实体类(其中类属性包括List等类型) Java实体类: SearchFilter 类 1 publ ...

  8. java批量将多文件打包成zip格式

    public void createzip(){ List<File> nFileList = new ArrayList<File>(); nFileList.add(new ...

  9. EF6学习笔记(六) 创建复杂的数据模型

    EF6学习笔记总目录:ASP.NET MVC5 及 EF6 学习笔记 - (目录整理) 本篇原文地址:Creating a More Complex Data Model 本篇讲的比较碎,很多内容本人 ...

  10. php SQL 防注入的一些经验

    产生原因 一方面自己没这方面的意识,有些数据没有经过严格的验证,然后直接拼接 SQL 去查询.导致漏洞产生,比如: $id = $_GET['id']; $sql = "SELECT nam ...