您现在的位置是:首页 > 正文

go语言中slice的容量和内存地址

2024-04-01 02:47:20阅读 2

问题由来。

package main
/*
#include <stdlib.h>
void* makeslice(size_t memsize) {
    return malloc(memsize);
}
*/
import "C"
import "unsafe"
func makeByteSlize(n int) []byte {
    p := C.makeslice(C.size_t(n))
    return ((*[1 << 31]byte)(p))[0:n:n]
}
func freeByteSlice(p []byte) {
    C.free(unsafe.Pointer(&p[0]))
}
func main() {
    s := makeByteSlize(1<<31)
    s[len(s)-1] = 255
    print(s[len(s)-1])
    //在这里加一句s = append(s,1),最终会报错
    freeByteSlice(s)
}

上方是一个利用CGO机制申请超过2GB大小的slice的程序,但是我在后面加上一句append语句后,就会报内存错误。

后面发现,是因为append导致了扩容,触发了内存搬移,而free函数传入的指针仍然指向了搬移之前的内存段,这就导致了错误。

下面是关于slice的一些需要注意的点。

  1. 对于slice的赋值语句,如果没有指定容量,那么容量会与赋值等式的右值一致。
var arr = []int{0,1,2}
nrr := arr[:1]

     上方语句执行后,nrr的cap是3而不是1。

    2.当slice不断append直到超过容量时,容量为变为原来的2倍。

    3.当slice发生容量改变时,会发生内存搬移。

var arr = []int{0,1,2}
nrr := arr[:2:2]
println(unsafe.Pointer(&arr[1]))
println(unsafe.Pointer(&nrr[1]))
nrr = append(nrr,3)
println(unsafe.Pointer(&arr[1]))
println(unsafe.Pointer(&nrr[1]))

当nrr的容量扩充后元素地址发生了改变,但是原本的那部分内存并没有被回收,因为arr仍然在引用那部分内存。如果没有这种引用关系,只是单纯对一个slice进行不断的append的话,原有的内存是会被回收的。slice的内容部分永远都是连续的内存空间。

  4.用切片运算符赋值时限定容量可以限定影响

var arr = []int{0,1,2}
nrr := arr[:2:2]
nrr = append(nrr,4)
println(arr[2])

//output : 2
var arr = []int{0,1,2}
nrr := arr[:2]
nrr = append(nrr,4)
println(arr[2])

//output : 4

从上面两个程序就可以看出设置容量的重要性了,第一段代码设置了容量为2,当发生扩容的时候,内存会进行搬移,之后arr和nrr的内容就不是同一段内存了,这样nrr的第三个元素,也就是4,不会影响到arr的内存。

第二个程序中nrr的初始容量是3,因此append之后并不需要扩容,因此arr和nrr的内容分布在同一段内存,这样就导致arr的第三个元素被4覆盖。

网站文章

  • Linux内存管理 - PAGE_OFFSET理解

    Linux内存管理 - PAGE_OFFSET理解     PAGE_OFFSET 代表的是内核空间和用户空间对虚拟地址空间的划分,对不同的体系结构不同。比如在32位系统中3G-4G 属于内核使用的内存空间,所以 PAGE_OFFSET = 0xC0000000。在X86-64架构下是ffff880000000000。可以看到内核程序可以可以访问从PAGE_OFFSET 之

    2024-04-01 02:47:13
  • 达梦8全量备份和增量备份备份策略

    达梦8全量备份和增量备份备份策略

    使用SYSDBA登录数据库manager工具,输入以下SQL语句,并执行。

    2024-04-01 02:46:32
  • 软件测试员200题(练习)

    所谓的“录制-回放”,就是先使用自动化工具由手工完成一遍需要测试的流程,同时由计算机记录下这个流程期间操作,并形成特定的( )。① 测试用例 ② 测试人员的分配 ③ 测试的度量标准 ④ 测试工具的选用...

    2024-04-01 02:46:24
  • 项目启动报java.lang.IllegalAccessError: tried to access method 热门推荐

    项目启动报java.lang.IllegalAccessError: tried to access method 热门推荐

    最近在对接京东代扣相关的业务,拿到京东的Demo,可以很快地把整套的流程跑下来,但当把Demo集成到项目中时,只要启动项目就不停地报错,错误信息如下:2017-10-13 19:34:18 ERROR _500_jsp _jspService - Handler processing failed; nested exception is java.lang.IllegalAccessError:

    2024-04-01 02:46:16
  • Tor

    Tor

    先打开这个网站 https://bridges.torproject.org/ Step #1:下载Tor浏览器 Step #2:获取bridges Step #3:在Tor浏览器上添加网桥 Step #4:调出项目结构管理区域 把网桥全部复制进去 在点击连接 注:连接第一次的时候比较慢 -End- 暗网搜索引擎 http://www.onion.l

    2024-04-01 02:45:37
  • CPU缓存那些事儿

    CPU缓存那些事儿

    CPU高速缓存集成于CPU的内部,其是CPU可以高效运行的成分之一,本文围绕下面三个话题来讲解CPU缓存的作用:为什么需要高速缓存?高速缓存的内部结构是怎样的?如何利用好cache,优化代码执行效率?...

    2024-04-01 02:45:29
  • IDEA-推荐几款好用的插件

    IDEA-推荐几款好用的插件

    .ignore git提交时过滤掉不需要提交的文件,很方便,有些本地文件是不需要提交到Git上的。 TranslationPlugin 对于不经常使用英语的同学来说,对类,变量,方法想取一个合适的名字...

    2024-04-01 02:45:22
  • 防病毒服务器部署位置,SymantecAntiVirus防病毒服务器安装配置使用指南.pdf

    Symantec AntiVirus 病毒服务器安装配置使用指南放入Symantec AntiVirus 安装光盘自启动 (或点击应用程序setup )后,选择 “安装管理员工具”。如...

    2024-04-01 02:44:39
  • javascript数组常用api 方法

    本文总结了javascript常用的数组的方法包括 forEach filter map join concat sort splice indexOf reverse find every push unshift pop shift等

    2024-04-01 02:44:31
  • IDEA 设置类注释,方法注释 /**

    IDEA 设置类注释,方法注释 /**

    一、类注释 打开: File → Settings → Editor → File and Code Templates 在class上方设置下放格式: /** * @Description: * @...

    2024-04-01 02:44:24