首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

下面的两个go代码有什么不同,为什么使用了这么多不同的内存

下面的两个Go代码有什么不同,为什么使用了这么多不同的内存?

代码1:

代码语言:txt
复制
package main

import "fmt"

func main() {
    var a []int
    for i := 0; i < 1000000; i++ {
        a = append(a, i)
    }
    fmt.Println(len(a))
}

代码2:

代码语言:txt
复制
package main

import "fmt"

func main() {
    a := make([]int, 0, 1000000)
    for i := 0; i < 1000000; i++ {
        a = append(a, i)
    }
    fmt.Println(len(a))
}

这两段代码的不同之处在于内存分配的方式和内存使用情况。

代码1中,使用了切片的默认初始化方式,即var a []int,这样的切片长度为0,容量为0。在循环中通过append函数向切片中添加元素,每次添加元素时,如果切片的容量不足,会重新分配更大的内存空间,并将原有的元素复制到新的内存空间中。这种方式会导致频繁的内存分配和复制操作,消耗较多的内存和时间。

代码2中,使用了make函数初始化切片,指定了切片的长度为0,容量为1000000,即a := make([]int, 0, 1000000)。在循环中通过append函数向切片中添加元素,如果切片的容量不足,会自动扩容,但是由于初始容量已经足够,不需要频繁的内存分配和复制操作,因此效率更高,消耗的内存也较少。

综上所述,代码2使用了更少的内存,因为它避免了频繁的内存分配和复制操作。在处理大量数据时,尽量预先分配足够的内存空间,可以提高程序的性能和效率。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

探索 Go 语言中的内存对齐:为什么结构体大小会有所不同?

理解内存对齐不仅可以帮助我们写出更高效的代码,还能避免一些潜在的性能陷阱。 在这篇文章中,我们将通过一个简单的例子来探讨 Go 语言中的内存对齐机制,以及为什么相似的结构体在内存中会占用不同的大小。...它们的字段基本相同,只是排列顺序不同。然后,我们使用 unsafe.Sizeof 来查看这两个结构体在内存中的大小。...结果却令人惊讶:结构体 A 的大小是 40 字节,而结构体 B 的大小是 48 字节。为什么会出现这样的差异呢?这就是我们今天要讨论的内存对齐的作用。...内存对齐概念 内存对齐是指编译器为了优化内存访问速度,而对数据在内存中的位置进行调整的一种策略。不同类型的数据在内存中的对齐要求不同,例如: int8 类型的变量通常对齐到 1 字节边界。...结构体内存布局解析 让我们深入分析一下 A 和 B 两个结构体的内存布局,看看编译器是如何为它们分配内存的。

8810

Golang 是否有必要内存对齐?

可见不同的字段顺序,最终决定 struct 的内存大小,所以有时候合理的字段顺序可以减少内存的开销。 这是为什么呢?因为有内存对齐的存在,编译器使用了内存对齐,那么最后的大小结果就会不一样。...至于为什么要做对齐,主要考虑下面两个原因: 平台(移植性) 不是所有的硬件平台都能够访问任意地址上的任意数据。...那么也就不难理解,为什么调整结构体内成员变量的字段顺序就能达到缩小结构体占用大小的疑问了,是因为巧妙地减少了 padding 的存在。让它们更 “紧凑” 了。...Stats Stats } 说了这么多,但是在我们实际编码的时候,多数情况都不会考虑到最优的内存对齐。那有没有什么办法能自动检测当前的内存布局是最优呢?答案是:有的。...^ 提示有一处 struct 可以优化,来看一下这个 struct 的定义: type SASL struct { Enable bool Username string

2K31
  • Go每日一库之87:zap

    /go.uber.org/zap QA 设计问题 为什么要在Logger性能上花费这么多精力呢?...有关为什么启用抽样的更多详细信息,请参见"为什么使用示例应用日志"中启用采样. 为什么要使用示例应用程序日志? 应用程序经常会遇到错误,无论是因为错误还是因为用户使用错误。...为什么结构化的日志 API 除了接受字段之外还可以接收消息? 主观上,我们发现在结构化上下文中附带一个简短的描述是有帮助的。这在开发过程中并不关键,但它使调试和操作不熟悉的系统更加容易。...要么zap安装错误,要么您引用了代码中的错误包名。...如果你遵循两个简单的规则,就会正常工作:安装zapgo get -u go.uber.org/zap并始终导入它在你的代码import "go.uber.org/zap",代码不应包含任何对github.com

    68440

    指针那么容易出错,为什么Go还保留?

    如果你想知道为什么 Go 的运行效率会那么快? 为什么你的程序老是报 invalid memory address or nil pointer dereference?...计算机最重要的两个硬件就是 CPU 和内存吧,CPU 负责计算,内存负责临时存储数据。 我们在写代码时,定义的变量在程序运行时,这些变量都被放在了内存里面,那内存是怎么存数据呢?...Go语言里面的指针 Go 里面并没完全抛弃指针,因为在很多时候有指针的存在,在效率上会高很多。...而在变量前面放 & 这个字符,就是取这个变量的指针。 到目前为止,Go 指针的核心知识点就这么多,剩下的都是围绕这些在开展。...初始化时就要求分配地址就好了,比如这样: var b *int = new(int) 但是我们一般不这么写,会结合 Go 的类型自动推断来处理,如下: b := new(int) 什么情况下使用指针

    32620

    女朋友问我:小松子,你知道Go语言参数传递是传值还是传引用吗?

    我们画个图来解释一下: 什么是引用传递 学习过其他语言的同学,对这个引用传递应该很熟悉,比如C++使用者,在C++中,函数参数的传递方式有引用传递。...改动后的值是 10 所以通过输出我们可以看到,这是一个指针的拷贝,因为存放这两个指针的内存地址是不同的,虽然指针的值相同,但是是两个不同的指针。...等等,好像好落下了点什么,说好的go中只有值传递呢,为什么chan、map、slice类型传递却可以改变其中的值呢?白着急,我们依次来验证一下。 slice也是值传递吗?...说了这么多,最后再做一个总结吧,为什么slice也是值传递。之所以对于引用类型的传递可以修改原内容的数据,这是因为在底层默认使用该引用类型的指针进行传递,但也是使用指针的副本,依旧是值传递。...出个题考验你们一下 欢迎在评论区留下你的答案~~~ 既然你们都知道了golang只有值传递,那么这段代码来帮我分析一下吧,这里的值能修改成功,为什么使用append不会发生扩容?

    35210

    【云+社区年度征文】我是如何 3 小时上手 Golang 的

    我在学 C 语言的时候,书上和老师都说“指针就是一个地址”,但是我觉得很奇怪,“指针”既然是一个“地址”,为什么不直接了当的说它是一个“地址”,而是要称呼它为“指针”。...、Go 编译器版本的不同而不同),因此只要在变量前使用 & 就可以得到变量的地址,看下面的示意图。...通常,参数的传递是进行一次内存的拷贝,无论是 值传递,还是 引用传递,实时上都是进行内存的拷贝,只是拷贝的内容有所不同。...图片.png 从上面的示意图中可以清楚的看出 main 函数中局部整型变量 i 和 test111 函数中两个参数的关系,已经内存的分布。...关于函数传参的部分,就整理这么多。接下来开始整理一下关于面向对象的部分。 面向对象 面向对象有几大特性,分别是 封装、继承 和 多态。

    73380

    18张图解密新时代内存分配器TCMalloc

    (图2) 结论:FreeList里一个节点最小为8字节 备注:因为要存指针,指针的大小为8字节,为什么?可以参考上篇文章《64位平台下,指针自身的大小为什么是8字节?》...Page的概念 操作系统是按Page管理内存的,本文中1Page为8KB,如下图所示: 备注:操作系统为什么按`Page`管理内存?不在本文范围。 ?...(图9) 接着,ThreadCache其实被线程持有,为什么呢? 答案:减少线程之间的竞争,分配内存时减少锁的过程。 这也是为什么叫`Thread Cache Alloc`的原因。...解密PageHeap PageHeap主要负责管理不同规格的Span,相同规格的Span构成SpanList(可回顾上文SpanList的概念)。 什么是相同规格的Span?...Processon ---- Go轻松进阶系列 更多文章 由浅到深,入门Go语言Map实现原理 64位平台下,指针自身的大小为什么是8字节? ? ?

    2K10

    《go 语言程序设计》读书笔记(六)Goroutine与系统线程的区别

    而goroutine的栈的最大值有1GB,比传统的固定大小的线程栈要大得多,尽管一般情况下,大多goroutine都不需要这么大的栈。 goroutine 调度 OS线程会被操作系统内核调度。...GOMAXPROCS Go的调度器使用了一个叫做GOMAXPROCS的变量来决定会有多少个操作系统的线程同时执行Go的代码。...其默认的值是运行机器上的CPU的核心数,所以在一个有8个核心的机器上时,调度器一次会在8个OS线程上去调度GO代码。(GOMAXPROCS是前面说的m:n调度中的n)。...在第二次执行时,我们使用了两个操作系统线程,所以两个goroutine可以一起被执行,以同样的频率交替打印0和1。...Go鼓励更为简单的模式,这种模式下参数对函数的影响都是显式的。这样不仅使程序变得更易读,而且会让我们自由地向一些给定的函数分配子任务时不用担心其身份信息影响行为。

    48010

    先聊聊「内存分配」,再聊聊Go的「逃逸分析」

    要搞清楚GO的逃逸分析一定要先搞清楚内存分配和堆栈: 内存分配既可以分配到堆中,也可以分配到栈中。 什么样的数据会被分配到栈中,什么样的数据又会被分配到堆中呢? GO语言是如何进行内存分配的呢?...其设计初衷和实现原理是什么呢? 我们先来聊一下内存管理、堆、栈的知识点: 内存管理 内存管理主要包括两个动作:分配与释放。逃逸分析就是服务于内存分配。...堆有时需要加锁:堆上的内存,有时需要加锁防止多线程冲突 延伸知识点:为什么堆上的内存有时需要加锁?而不是一直需要加锁呢?...变量大小不确定时 我们再简单修改一下上面的代码: package main func test() { l := 1 a := make([]int, l, l) for i := 0; i 的开发模式,我们一定是在不断的需求变化,业务变化中求得平衡的: 举个例子 举个日常开发中函数传参的例子: 有些场景下我们不应该传递结构体指针,而应该直接传递结构体。 为什么会这样呢?

    52510

    Go中常见错误100例教程:第1章 Go易学难精

    1.1.3 安全性 Go是一门静态类型的语言。因此,类型检查是在编译阶段而非运行时进行的。这样就保证了我们编写的代码在大多数情况下是类型安全的。 此外,Go具有垃圾收集器来帮助开发者处理内存管理。...通过内存共享促进消息传递的基本原理是什么呢? 今天,所有的CPU都有不同级别的缓存来加速对主内存(RAM)的访问。跨不同线程共享的变量可能会重复多次。...因此,共享内存是现代CPU提供的一种错觉(我们将在并发章节深入研究这些概念)。 采用消息传递符合现代cpu的构建方式,这在大多数情况下对性能有重大影响。此外,她使复杂的交互更容易推理。...然而,在大多数情况下,我们应该支持消息传递的方法,主要是因为,正如所讨论的,这种方法利用了现代CPU的构建方式。 消息传递是一种强大的并发方法,但它不能防止数据竞争。...本书疑意在通过收集和展示Go语言各个方面的100个常见错误来帮助你成为一名熟练的开发人员:基础知识、代码组织、数据和控制结构、字符串、函数和方法、错误管理、并发、测试、优化和生产。

    29930

    「 不懂就问 」esbuild 为什么这么快?

    今天我们就来探索一下: 为什么 esbuild 这么快下文的主要内容: 几组性能数据对比 为什么 esbuild 这么快 esbuild upcoming roadmap esbuild 在 vite...中的运用 为什么生产环境仍需打包为何vite不用 esbuild 打包?...为什么 esbuild 这么快 ? 有以下几个原因。 (为了保证内容的准确性, 以下内容翻译自 esbuild 官网。) 1. 它是用 Go 语言编写的,并可以编译为本地代码。...每次运行打包器时,JavaScript VM 都会在没有任何优化提示的情况下看到打包程序的代码。...这样会占用更多内存,并且会减慢速度。 Go的另一个好处是它可以将内容紧凑地存储在内存中,从而使它可以使用更少的内存并在CPU缓存中容纳更多内容。

    1.3K10

    实战:使用rust开发动态链接库并在Golang中使用

    了解Rust为什么比一些常用的语言(如Golang、Java等)更适合开发通用二进制库 了解一下Rust开发C-FFI库的方法,并介绍一些个人实际使用中遇到的问题(也可能是我太菜) 了解一下Golang...中Cgo的使用 有很多朋友在纠结Golang和Rust选哪个,通过本次分享,加深对两个语言的了解,为大家做选择多一些参考 分享目录 Get hands dirty Rust在开发二进制库上的优势 为什么选择...默认情况下,Rust编译器认为我们定义的函数都是由Rust程序调用的,这时编译器默认对函数名进行了混淆,为什么要混淆的原因大家可以参考:https://internals.rust-lang.org/t...接下来还有两个函数,我们也依次来看一下他们在内存使用上有什么差异。为了缩短篇幅,相同的注释内容就被删除了。...因为Go是有垃圾回收的,GoString所对应的内存地址是在Go Runtime的内存分配器管辖范围里的,而cgo中为了实现CFFI的调用,需要使用操作系统的内存分配器,Go语言中这两个内存分配器对内存管理的方式不一样

    2.8K10

    Java VS Go 还在纠结怎么选吗,(资深后端带你深度对比)

    接下来我们从多个维度对比一下Go和Java, 为什么要比较它们?   ...随着越来越多的后台Java应用转移到Go, 我觉得有必要来深入的聊一聊这两个语言了,我们从语言层面(语言特性、速度和易用性、内存使用等方面)、社区活跃度来PK一下,进而总结出这两个语言的优缺点以及这两个语言的开发方向...其次Java有不同权限的访问修饰符,为每个应用程序创建不同级别的访问权限。从 Go 1.13 开始,go 命令默认使用 Go 模块镜像和 Go 校验和数据库下载和验证模块,语言层面内置安全策略。...其实除了上面这些维度,还有很多维度,比如泛型,异常,函数式编程等语法特点,这些我们就一笔带过了,那么基于以上的比较我们可以总结一下这两个语言的优缺点: 三、优缺点总结 Go的优点 代码简洁性 静态类型可编译成机器码直接运行...结论: 学 最后   终于到最后了,写完这篇文章已经是凌晨12:29了,感谢各位能看到最后,希望以上的对比能给你带来一点帮助,写这么多也不容易,感谢大家看到这里,有什么意见或者建议可以留言一起讨论,看到后第一时间回复

    22.3K54

    本立道生,Go interface背后的对象模型

    二哥花了不少篇幅剖析容器网络的底层信息,也拿Cilium做例子介绍了CNI是什么,它是如何配合K8s完成容器网络相关的配置和维护的。 为什么要花这么多篇来介绍网络呢?...本文来聊聊这方面的内容,希望你看完后和顿悟之前的我有一样的感觉:看前咬紧笔头,困惑不已。看后恍然大悟,频频点头以示认同。同时又嘲笑自己,为何之前总是无法参透其中的奥秘?...举个例子,我们知道在C++中对于class,有两种data member: statci和非static,以及三种member function:static,非static和virtual,如上面的示例所示...为什么呢?引用Stanley B....我们来思考三个问题: 接口值到底是什么?它是指针吗?如果是的话,指针所指向的那块内存内容是什么? any.(Stringer)这样的类型断言到底是如何实现的? 反射所依赖的底层数据结构到底是什么?

    36130

    golang | 是返回struct还是返回struct的指针

    当我们定义一个函数时,是返回结构体呢,还是返回指向结构体的指针呢? 对于这个问题,我想大部分人的回答,肯定都是返回指针,因为这样可以避免结构体的拷贝,使代码的效率更高,性能更好。 但真的是这样吗?...写个benchmark测试下: ? 执行看下结果: ? 这两个benchmark的时间几乎是相等的,其结果并不像我们预料的那样,返回指针的形式会更快些。 为什么呢?...这次结果显示,f2函数,即返回结构体形式,比f1函数,即返回指针的形式,居然快了将近5倍,意不意外? 这是为什么呢? 其实在上图中,就有一些线索。...那为什么在堆上分配内存,会比在栈上分配内存慢这么多呢?...有两点原因,一是在堆上分配内存的函数runtime.newobject,其本身逻辑就比较复杂,二是堆上分配的内存,后期还要通过gc来对其进行内存回收,这些逻辑加起来,远比在栈上分配内存,外加一次拷贝操作要耗时的多

    4K41

    译 - 为什么要学习Go?

    由于每个线程消耗大约1MB的内存堆大小,最终如果您开始旋转数千个线程,它们将对堆施加巨大压力,并由于内存不足而导致关闭。另外,如果您想在两个或多个线程之间进行通信,则非常困难。...另一方面,Go于2009年发布,当时多核处理器已经可用。这就是为什么走的是与保持并发考虑建造。Go具有goroutines而不是线程。它们从堆中消耗了将近2KB的内存。...以上所有这些,使Go在处理Java,C和C ++之类的并发性方面非常强大,同时保持了并发执行代码的平稳性和Erlang之类的美丽。 ? `Go兼顾了两个世界。...通过删除继承,Go还可轻松理解代码(因为在查看一段代码时没有要查看的超类)。 没有构造函数。 没有注释。 没有泛型。 没有例外。 上述变化使Go与其他语言完全不同,并且使Go编程也与其他语言不同。...(来源:https : //github.com/golang/go/wiki/GoUsers) 结论: 尽管Go与其他面向对象的语言有很大不同,但它仍然是相同的野兽。

    59450

    Go内存分配和逃逸分析-实践总结篇

    GO语言是如何进行内存分配的呢?其设计初衷和实现原理是什么呢? 要搞清楚上面的问题,我们先来聊一下内存管理和堆、栈的知识点: 内存管理 内存管理主要包括两个动作:分配与释放。...堆有时需要加锁:堆上的内存,有时需要加锁防止多线程冲突 延伸知识点:为什么堆上的内存有时需要加锁?而不是一直需要加锁呢?...逃逸分析原则 Go语言虽然没有明确说明逃逸分析原则,但是有以下几点准则,是可以参考的。...变量大小不确定时 我们再简单修改一下上面的代码: package main func test() { l := 1 a := make([]int, l, l) for i := 0; i 的开发模式,我们一定是在不断的需求变化,业务变化中求得平衡的: 举个栗子 举个日常开发中函数传参例子: 有些场景下我们不应该传递结构体指针,而应该直接传递结构体。 为什么会这样呢?

    44061

    go语言调度器源代码情景分析之四:函数调用栈

    数据区,包括程序的全局变量和静态变量(c语言有静态变量,而go没有),与代码区一样,程序加载完毕后数据区的大小也不会发生改变。 堆,程序运行时动态分配的内存都位于堆中,这部分内存由内存分配器负责管理。...值的一提的是传统的c/c++代码就必须小心处理内存的分配和释放,而在go语言中,有垃圾回收器帮助我们,所以程序员只管申请内存,而不用管内存的释放,这大大降低了程序员的心智负担,这不光是提高了程序员的生产力...,因为不同的函数局部变量的个数以及所占内存的大小都不尽相同; 有些编译器比如gcc会把参数和返回值放在寄存器中而不是栈中,go语言中函数的参数和返回值都是放在栈上的; 随着程序的运行,如果C、B两个函数都执行完成并返回到了...可以看到,现在D函数的栈帧其实使用的是之前调用B、C两个函数所使用的栈内存,这没有问题,因为B和C函数已经执行完了,现在D函数重用了这块内存,这也是为什么在C语言中绝对不要返回函数局部变量的地址,因为同一个地址的栈内存会被重用...从上图可以看出,即使是同一个函数,每次调用都会产生一个不同的栈帧,因此对于递归函数,每递归一次都会消耗一定的栈内存,如果递归层数太多就有导致栈溢出的风险,这也是为什么我们在实际的开发过程中应该尽量避免使用递归函数的原因之一

    1.2K10

    Go内存分配和逃逸分析-理论篇

    GO语言是如何进行内存分配的呢?其设计初衷和实现原理是什么呢? 要搞清楚上面的问题,我们先来聊一下内存管理和堆、栈的知识点: 内存管理 内存管理主要包括两个动作:分配与释放。...堆有时需要加锁:堆上的内存,有时需要加锁防止多线程冲突 延伸知识点:为什么堆上的内存有时需要加锁?而不是一直需要加锁呢?...逃逸分析原则 Go语言虽然没有明确说明逃逸分析原则,但是有以下几点准则,是可以参考的。...变量大小不确定时 我们再简单修改一下上面的代码: package main func test() { l := 1 a := make([]int, l, l) for i := 0; i 的开发模式,我们一定是在不断的需求变化,业务变化中求得平衡的: 举个栗子 举个日常开发中函数传参例子: 有些场景下我们不应该传递结构体指针,而应该直接传递结构体。 为什么会这样呢?

    31630
    领券