golang内存分配 (二)

源码基于go1.8rc3。

首先看看mheap的数据结构

// mheap本身只包含"free[]" and "large"数组
// 但其他的全局数据也在这里
// mheap 禁止从堆上创建,因包含的mSpanLists不能从堆上创建
type mheap struct {
	lock      mutex
	free      [_MaxMHeapList]mSpanList // free lists of given length
	freelarge mSpanList                // free lists length >= _MaxMHeapList
	busy      [_MaxMHeapList]mSpanList // busy lists of large objects of given length
	busylarge mSpanList                // busy lists of large objects length >= _MaxMHeapList
	sweepgen  uint32                   // sweep generation, see comment in mspan
	sweepdone uint32                   // all spans are swept

    // allspans是所有曾经创建过的mspans的数组,每个mspan只存储一次
    // allspans的内存是手动管理的,随着堆的增长,可以重新创建或移动
    // 一般来说,allspans是被mheap.lock所保护,当释放backing store时,锁用于防止并发的访问
    // 在STW期间访问可能不会持有锁,但必须确保分配不会发生在访问的时候(因为这可能释放backing store)
	allspans []*mspan // all spans out there

    // spans是一张查询表,用于映射虚拟地址页的id到*mspan
    // 对于已经分配spans,它们的页映射到span本身
    // 对于空闲的spans,只有最低位和最高位的页映射到span本身
    // 内部的页映射到一个固定的span
    // 对于从未分配过的页,span是空的
    // 空间分配在一个预先储备好大块的地址上,因此它可以不断增长而不需要移动。len(spans)是分配出去的内存,
    // cap(spans)是所有储备的内存空间
	spans []*mspan

    // sweepSpans包含两个mspan栈,一个是已经清理的使用中的spans,一个是未清理的使用中的spans。
    // 这两个角色在每个GC周期相互转换,因此sweepgen这个字段在每个GC周期中增加2,这意味着清理完的spans
    // 存放在sweepSpans[sweepgen/2%2],而未清理的spans存放在sweepSpans[1-sweepgen/2%2]。
    // 清理过程会把spans从未清理的栈中取出来,并把使用中的spans放到清理完成的栈中。同样的,分配一个使用中
    // 的span会把它放到已清理的栈中
	sweepSpans [2]gcSweepBuf

	_ uint32 // align uint64 fields on 32-bit for atomics

	// Proportional sweep
	pagesInUse        uint64  // pages of spans in stats _MSpanInUse; R/W with mheap.lock
	spanBytesAlloc    uint64  // bytes of spans allocated this cycle; updated atomically
	pagesSwept        uint64  // pages swept this cycle; updated atomically
	sweepPagesPerByte float64 // proportional sweep ratio; written with lock, read without
	// TODO(austin): pagesInUse should be a uintptr, but the 386
	// compiler can't 8-byte align fields.

	// Malloc stats.
	largefree  uint64                  // bytes freed for large objects (>maxsmallsize)
	nlargefree uint64                  // number of frees for large objects (>maxsmallsize)
	nsmallfree [_NumSizeClasses]uint64 // number of frees for small objects (<=maxsmallsize)

	// range of addresses we might see in the heap
	bitmap         uintptr // Points to one byte past the end of the bitmap
	bitmap_mapped  uintptr
	arena_start    uintptr
	arena_used     uintptr // always mHeap_Map{Bits,Spans} before updating
	arena_end      uintptr
	arena_reserved bool

	// central free lists for small size classes.
	// the padding makes sure that the MCentrals are
	// spaced CacheLineSize bytes apart, so that each MCentral.lock
	// gets its own cache line.
	central [_NumSizeClasses]struct {
		mcentral mcentral
		pad      [sys.CacheLineSize]byte
	}

	spanalloc             fixalloc // allocator for span*
	cachealloc            fixalloc // allocator for mcache*
	specialfinalizeralloc fixalloc // allocator for specialfinalizer*
	specialprofilealloc   fixalloc // allocator for specialprofile*
	speciallock           mutex    // lock for special record allocators.
}

原文:大专栏  golang内存分配 (二)

原文地址:https://www.cnblogs.com/petewell/p/11607035.html

时间: 2024-08-28 05:30:46

golang内存分配 (二)的相关文章

一维和二维数组 动态内存分配

一维数组的动态内存分配 #include "stdafx.h" #include <iostream> using namespace std; int main() { int length,i; int *p; cin>>length; p=new int[length]; for(i=0;i<length;i++) { p[i]=i; //不要写成*p[i]=i; cout<<p[i]<<endl; //不要写成cout<

C++二维数组动态内存分配

对于二维数组和二维指针的内存的分配 这里首选说一下一维指针和一维数组的内存分配情况. 一维: 数组:形如int  a[5];这里定义了一个一维数组a,并且数组的元素个数是5,这里的a是这五个元素的整体表示,也就是通过a我们能找到这五个元素.注意:a是代表数组第一个元素的首地址.&a是代表数组的地址,虽然它们的值相同. 指针: int *p = NULL:这里p是一个指针,它指向的是计算 机内一块存储int类型的内存.P = a;就是让p等于刚才申请的数组的第一个元素的地址.所以通过p我们也能找到

动态内存分配连续内存空间的二维数组

可以直接使用一维数组来模拟二维数组,下面的代码就是在此基础上,用一个二级指针指向一维数组的相应地方,详见代码 #include <stdio.h> #include <malloc.h> int main() { int row,col,i,j,n=0; row=col=3; //malloc连续内存的二维数组 int **arr=(int**)malloc(row*sizeof(int*));//分配二维数组 arr[0]=(int*)malloc(row*col*sizeof(

【C语言天天练(二四)】内存分配

引言: 对于C语言程序,了解它执行时在内存中是怎样分配的对于我们理解它的执行机制是很实用的.以下就总结一下C语言程序的一些内存分配知识. 一 一段C程序.编译连接后形成的可运行文件一般有代码段.数据段.堆和栈等几部分组成.当中数据段又包含仅仅读数据段.已初始化的读写数据段和未初始化的BSS段.例如以下图所看到的: 文本段:存放程序运行的代码. 数据段: 1>仅仅读数据段: 仅仅读数据段是程序使用的一些不会被更改的数据,使用这些数据的方式类似查表式的操作,因为这些变量不须要更改,因此仅仅须要放置在

垃圾收集器与内存分配策略(二)

垃圾收集算法简介 1.标记-清除算法       标记-清除算法主要分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一进行回收.对象的标记过程在垃圾收集器与内存分配策略(一)中已经介绍过. 存在的问题:一是效率问题,标记和清除的效率都不高:二是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时无法找到足够的内存而不得不提前触发另一次垃圾收集动作. 2.复制算法       复制算法:它将内存按照容量划分为大小

二、动态内存分配与使用

1.malloc (1)malloc分配函数:需要给出申请空间大小(以字节为单位) (2)返回值是一个首地址,用指针接收 (3)使用sizeof计算元素大小 (4)使用malloc函数申请内存空间,用完后需要释放,否则会造成内存泄露 (5)释放函数free需要指向分配内存的指针 (6)基本形式:void *malloc(unsigned int size); (7)分配指定大小的内存空间,但是不会把分配的空间清0 (8)free(指针);//释放堆空间,标记删除,不清楚内容 (9)示例: ①ma

垃圾收集器与内存分配策略(二)之垃圾收集算法

垃圾收集器与内存分配策略(二)--垃圾收集算法 Java JVM 垃圾回收 简单了解算法的思想 1. 标记-清除算法 标记-清除算法分为标记和清除二个阶段:首先标记出需要回收的对象(详见上一节的可达性分析找出存活对象),在标记完成后统一回收所有被标记的对象. 缺点: 1.标记和清除二个过程的效率都不高 2.空间问题,标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后再程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作. 2. 复制算法 复制算

JVM总结(二):JVM的内存分配策略

这节我们总结一下JVM中的内存分配策略.目录如下: 内存分配策略 对象优先在新生代Eden分配 大对象直接进入老年代 长期存活的对象将进入老年代 动态对象年龄判定 空间分配担保 内存分配策略 Java技术体系中所提倡的自动内存管理可以归结于两个部分:给对象分配内存以及回收分配给对象的内存. 我们都知道,Java对象分配,都是在Java堆上进行分配的,虽然存在JIT编译后被拆分为标量类型并简介地在栈上进行分配.如果采用分代算法,那么新生的对象是分配在新生代的Eden区上的.如果启动了本地线程分配缓

读Redis学C程序设计二:内存分配

内存分配对于C程序来说是一个核心问题,许多开源软件都会针对自己软件的需要定制自己的内存分配策略,redis也不例外.然而总的来说,redis并不是专门去管内存分配的东西,它的内存分配策略的最大特点在于加上了统计信息,这一点很重要.毕竟,redis是一个内存数据库,知道自己用了多少内存,还有多少内存可用是它非常需要关注的问题.我们来看zmalloc里面的内容. 首先在zmalloc.h里面 #if defined(USE_TCMALLOC) #define ZMALLOC_LIB ("tcmall