Go运行时的内存分配器以及消耗指定大小的内存(C语言)

对于go语言在运行时的一些内存分配,想要详细的了解,我们会用到自带的runtime.MemStats,有很多具体的细节实现,而不是简单的只看任务管理器中的内存分配。

我们先来看下这个记录内存分配器的结构体

type MemStats struct {
	Alloc uint64		#堆空间分配的字节数
	TotalAlloc uint64		#服务运行一直累积的总分配的堆空间,释放也不减少
	Sys uint64		#操作系统获取的内存
	Lookups uint64		#运行时执行的指针查找数,用于调试
	Mallocs uint64		#服务malloc的次数
	Frees uint64		#释放堆对象字节数
	HeapAlloc uint64		#服务分配的堆内存字节数
	HeapSys uint64		#系统分配的堆内存字节数
	HeapIdle uint64		#申请但未分配的堆内存或者回收了的堆内存字节数
	HeapInuse uint64		#正在使用的堆内存字节数
	HeapReleased uint64	#返回给OS的堆内存,类似C/C++中的free
	HeapObjects uint64	#堆内存块申请的量
	StackInuse uint64		#正在使用的栈字节数
	StackSys uint64		#系统分配的作为运行栈的内存
	MSpanInuse uint64		#用于测试用的结构体使用的字节数
	MSpanSys uint64		#系统为测试用的结构体分配的字节数
	MCacheInuse uint64	#结构体申请的字节数,不被视为垃圾回收	
	MCacheSys uint64		#操作系统申请的堆空间用于mcache的量
	BuckHashSys uint64	#用于剖析桶散列表的堆空间
	GCSys uint64		#垃圾回收标记元信息使用的内存
	OtherSys uint64		#golang系统架构占用的额外空间
	NextGC uint64		#垃圾回收器检视的内存大小
	LastGC uint64		#垃圾回收器最后一次执行时间
	PauseTotalNs uint64	#垃圾回收或者其他信息收集导致服务暂停的次数
	PauseNs [256]uint64	#一个循环队列,记录最近垃圾回收系统中断的时间
	PauseEnd [256]uint64	# 一个循环队列,记录最近垃圾回收系统中断的时间开始点
	NumGC uint32		#垃圾回收完成的次数
	NumForcedGC uint32	#服务调用runtime.GC()强制使用垃圾回收的次数
	// GODEBUG=gctrace=1.
	GCCPUFraction float64	#垃圾回收占用服务CPU工作的时间总和
				#如果有100个goroutine,垃圾回收的时间为1s,总占用100s	
	EnableGC bool		#是否启用GC,如果启用,即便GOGC=off也是启用的
	DebugGC bool
	#内存分配器使用情况
	BySize [61]struct {
		Size uint32
		Mallocs uint64
		Frees uint64
	}
}

看个具体的示例:

package main

import (
	"fmt"
	"runtime"
	"time"
)

// 内存使用情况
func PrintMemUsage() {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)
	fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc))
	fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc))
	fmt.Printf("\tSys = %v MiB", bToMb(m.Sys))
	fmt.Printf("\tNumGC = %v\n", m.NumGC)
}

// 转国际标(兆字节)
func bToMb(b uint64) uint64 {
	return b / 1024 / 1024
}
func main() {
	var s []string

	for i := 0; i < 100000000; i++ {
		s = append(s, "你好,寅恪光潜!")
	}
	PrintMemUsage()

	for {
		//runtime.GC() //调用GC进行内存回收
		PrintMemUsage()
		fmt.Println(s[0])
		time.Sleep(time.Second * 1)
	}
}
/*
C:\Users\Tony>go run test.go
Alloc = 5625 MiB        TotalAlloc = 9192 MiB   Sys = 8066 MiB  NumGC = 25
Alloc = 4486 MiB        TotalAlloc = 9192 MiB   Sys = 8066 MiB  NumGC = 26
你好,寅恪光潜!
Alloc = 4486 MiB        TotalAlloc = 9192 MiB   Sys = 8066 MiB  NumGC = 26
你好,寅恪光潜!
Alloc = 4486 MiB        TotalAlloc = 9192 MiB   Sys = 8066 MiB  NumGC = 26
你好,寅恪光潜!
Alloc = 4486 MiB        TotalAlloc = 9192 MiB   Sys = 8066 MiB  NumGC = 26
...
*/

然后去掉runtime.GC()注释,启用内存回收,出现如下效果:

/*
C:\Users\Tony>go run test.go
Alloc = 4486 MiB        TotalAlloc = 9192 MiB   Sys = 7050 MiB  NumGC = 26
Alloc = 1838 MiB        TotalAlloc = 9192 MiB   Sys = 7050 MiB  NumGC = 27
你好,寅恪光潜!
Alloc = 1838 MiB        TotalAlloc = 9192 MiB   Sys = 7050 MiB  NumGC = 28
你好,寅恪光潜!
Alloc = 1838 MiB        TotalAlloc = 9192 MiB   Sys = 7050 MiB  NumGC = 29
你好,寅恪光潜!
Alloc = 1838 MiB        TotalAlloc = 9192 MiB   Sys = 7050 MiB  NumGC = 30
...
*/

上面选取了几个成员变量,可以看出这个运行时的内存查看还是挺方便详细的。

有时候需要做内存压力测试等,我们可能会用到消耗一定的内存,没有Linux纯环境,我在WSL中运行,如果你也是Windows系统想要熟悉Linux也可以查阅:Windows版的Linux子系统(WSL)安装

malloc_mb.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#define UNIT (1024*1024)

int main(int argc, char *argv[])
{
    long long i = 0;
    int size = 0;

    if (argc != 2)
    {
        printf("请输入需要分配的内存值\n");
        return 1;
    }
    #unsigned long int strtoul(const char *nptr, char **endptr, int base);
    #unsigned long long int strtoull(const char *nptr, char **endptr,int base);
    size = strtoull(argv[1], NULL, 10);#字符串转换成数字,十进制
    if (size == 0)
    {
        printf("请输入大于0的内存值");
        return 1;
    }

    char *buff = (char *) malloc(size * UNIT);
    if (buff)
        printf("已分配%dMB\n", size);
    buff[0] = 1;

    for (i = 1; i < (size * UNIT); i++)
    {
        if (i%1024 == 0)
            buff[i] = buff[i-1]/8;
        else
            buff[i] = i/2;
    }
    pause();
}

编译成一个可执行文件:gcc malloc_mb.c -o malloc,目录下面将有个malloc文件,然后运行它:./malloc 1000
这样就会成功分配1000MB的内存!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寅恪光潜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值