范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

Golang切片原理

  在Golang语言开发过程中,我们经常会用到数组和切片数据结构,数组是固定长度的,而切片是可以扩张的数组,那么切片底层到底有什么不同?接下来我们来详细分析一下内部实现。一、内部数据结构
  首先我们来看一下数据结构type slice struct {     array unsafe.Pointer// 数据     len int             // 长度     cap int             // 容量 }
  这里的array其实是指向切片管理的内存块首地址,而len就是切片的实际使用大小,cap就是切片的容量。
  我们可以通过下面的代码输出slice:package main  import ( 	"fmt" 	"unsafe" )  func main() { 	  data := make([]int,0,3)  	  fmt.Println(unsafe.Sizeof(data),len(data),cap(data)) 	  // Output: 24,0,3  	  // 通过指针方式拿到切片内部的值 	  ptr := unsafe.Pointer(&data) 	  opt := (*[3]int)(ptr)  	  fmt.Println(opt[0],opt[1],opt[2]) 	  // Output: 824634891936,0,3  	  data = append(data, 4) 	  fmt.Println(unsafe.Sizeof(data)) 	  // Output: 24    	  shallowCopy := data[:1] 	  ptr1 := unsafe.Pointer(&shallowCopy) 	  opt1 := (*[3]int)(ptr1)    	  fmt.Println(opt1[0]) 	  // Output: 824634891936 }
  这么分析下来,我们可以了解如下内容:切片的数据结构大小是24,int占8字节,指针占8字节在不发生扩容的情况下,切片指向的首选地址不变常用的关于切片的方法有make,copy二、声明
  使用一个切片通常有两种方法:
  一种是var slice []int,称为声明;
  另一种是slice = make([]int, len, cap)这种方法,称为分配内存。三、创建make
  创建一个slice,实质上是在分配内存。func makeslice(et *_type, len, cap int) unsafe.Pointer {     // 获取需要申请的内存大小    mem, overflow := math.MulUintptr(et.size, uintptr(cap))    if overflow || mem > maxAlloc || len < 0 || len > cap {    	    mem, overflow := math.MulUintptr(et.size, uintptr(len))    	if overflow || mem > maxAlloc || len < 0 {    		  panicmakeslicelen() // 超过内存限制|超过最大分配量|长度小于0    	}    	    panicmakeslicecap() // 长度大于容量    }      // 分配内存      // runtime/malloc.go    return mallocgc(mem, et, true) }
  这里跟一下细节,math.MulUintptr是基于底层的指针计算乘法的,这样计算不会导致超出int大小,这个方法在后面会经常用到。func MulUintptr(a, b uintptr) (uintptr, bool) { 	  if a|b < 1<<(4*sys.PtrSize) || a == 0 { // sys.PtrSize=8 	  	  return a * b, false // a和b都小于32位,乘积肯定小于64位 	  } 	  overflow := b > MaxUintptr/a // MaxUintptr= ^uintptr(0),也就是64个1 	  return a * b, overflow }
  同样,对于int64的长度,也有对应的方法func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer { 	  len := int(len64) 	  if int64(len) != len64 { 	  	  panicmakeslicelen() 	  }    	  cap := int(cap64) 	  if int64(cap) != cap64 { 	  	  panicmakeslicecap() 	  }    	  return makeslice(et, len, cap) }
  而实际分配内存的操作调用mallocgc这个分配内存的函数,这个函数以后再分析。四、扩容机制
  我们了解切片和数组最大的不同就是切片能够自动扩容,接下来看看切片是如何扩容的func growslice(et *_type, old slice, cap int) slice {     // 前置条件 	  if cap < old.cap { 	  	  panic(errorString("growslice: cap out of range")) 	  }              // 如果新切片的长度为0,返回空数据,长度为旧切片的长度 	  if et.size == 0 {  	  	  return slice{unsafe.Pointer(&zerobase), old.len, cap} 	  }          // 1、先记录原先的容量 	  newcap := old.cap       // 2、尝试2倍扩容 	  doublecap := newcap + newcap 	  if cap > doublecap {             // 如果指定容量大于原有容量的2倍,则按新增容量申请 	  	  newcap = cap 	  } else {           // 3、如果指定容量小于原容量2倍,则按以下的计算方式为新容量 	  	  if old.len < 1024 { // 如果原容量小于1024,新容量是原容量的2倍 	  	  	  newcap = doublecap 	  	  } else { // 原容量大于1024,按原容量的1.25倍递增 	  	  	  for 0 < newcap && newcap < cap { 	  	  		    newcap += newcap / 4 	  	      } 	  	  	  if newcap <= 0 { // 校验容量是否溢出 	  	  		    newcap = cap 	  	  	  } 	  	  } 	  }    	  var overflow bool 	  var lenmem, newlenmem, capmem uintptr 	  // 为加速计算(不用乘除法)       // 对于2的幂,使用变位处理       // 下面的处理使内存对齐 	  switch { 	  case et.size == 1: 	  	  lenmem = uintptr(old.len) 	  	  newlenmem = uintptr(cap) 	  	  capmem = roundupsize(uintptr(newcap)) 	  	  overflow = uintptr(newcap) > maxAlloc 	  	  newcap = int(capmem) 	  case et.size == sys.PtrSize: 	  	  lenmem = uintptr(old.len) * sys.PtrSize 	  	  newlenmem = uintptr(cap) * sys.PtrSize 	  	  capmem = roundupsize(uintptr(newcap) * sys.PtrSize) 	  	  overflow = uintptr(newcap) > maxAlloc/sys.PtrSize 	  	  newcap = int(capmem / sys.PtrSize) 	  case isPowerOfTwo(et.size): // 2的幂 	  	  var shift uintptr 	  	  if sys.PtrSize == 8 { 	  	  	  // Mask shift for better code generation. 	  	  	  shift = uintptr(sys.Ctz64(uint64(et.size))) & 63 	  	  } else { 	  	  	  shift = uintptr(sys.Ctz32(uint32(et.size))) & 31 	  	  } 	  	  lenmem = uintptr(old.len) << shift 	  	  newlenmem = uintptr(cap) << shift 	  	  capmem = roundupsize(uintptr(newcap) << shift) 	  	  overflow = uintptr(newcap) > (maxAlloc >> shift) 	  	  newcap = int(capmem >> shift) 	  default: 	  	  lenmem = uintptr(old.len) * et.size 	  	  newlenmem = uintptr(cap) * et.size 	  	  capmem, overflow = math.MulUintptr(et.size, uintptr(newcap)) 	  	  capmem = roundupsize(capmem) 	  	  newcap = int(capmem / et.size) 	  }    	  // 判断是否会溢出,是否会超出可分配 	  if overflow || capmem > maxAlloc { 	  	  panic(errorString("growslice: cap out of range")) 	  }          // 内存分配 	  var p unsafe.Pointer 	  if et.ptrdata == 0 { 	  	  p = mallocgc(capmem, nil, false) 	  	  // 回收内存 	  	  memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem) 	  } else { 	  	  // Note: can"t use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory. 	  	  p = mallocgc(capmem, et, true) 	  	  if lenmem > 0 && writeBarrier.enabled { // gc 	  	  	  // Only shade the pointers in old.array since we know the destination slice p 	  	  	  // only contains nil pointers because it has been cleared during alloc. 	  	  	  bulkBarrierPreWriteSrcOnly(uintptr(p), uintptr(old.array), lenmem) 	  	  } 	  }       // 数据拷贝 	  memmove(p, old.array, lenmem)    	  return slice{p, old.len, newcap} }
  这里可以看到,growslice是返回了一个新的slice,也就是说如果发生了扩容,会发生拷贝。
  所以我们在使用过程中,如果预先知道容量,可以预先分配好容量再使用,能提高运行效率。五、深拷贝
  copy这个函数在内部实现为slicecopyfunc slicecopy(to, fm slice, width uintptr) int {     // 前置条件 	  if fm.len == 0 || to.len == 0 { 		    return 0 	  }  	  n := fm.len 	  if to.len < n { 		    n = to.len 	  }     // 元素长度为0,直接返回 	  if width == 0 { 		    return n 	  }  	  size := uintptr(n) * width     // 拷贝内存 	  if size == 1 { 		    *(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer 	  } else { 		    memmove(to.array, fm.array, size) 	  } 	  return n }
  还有关于字符串的拷贝func slicestringcopy(to []byte, fm string) int {     // 前置条件 	  if len(fm) == 0 || len(to) == 0 { 		    return 0 	  }  	  n := len(fm) 	  if len(to) < n { 		    n = len(to) 	  }  	  memmove(unsafe.Pointer(&to[0]), stringStructOf(&fm).str, uintptr(n)) 	  return n }
  这里显示了可以把string拷贝成[]byte,不能把[]byte拷贝成string。六、总结
  1、切片的数据结构是 array内存地址,len长度,cap容量
  2、make的时候需要注意 容量 * 长度 分配的内存大小要小于264,并且要小于可分配的内存量,同时长度不能大于容量。
  3、内存增长的过程:如果指定的容量大于原先的2倍,就按照指定的容量如果原先的容量小于1024,按2倍容量扩张如果原先的容量大于1024,就按1.25倍扩张,会小于指定的容量容量大小确定完之后,会进行内存对齐
  4、当发生内存扩容时,会发生拷贝数据的现象,影响程序运行的效率,如果可以,要先分配好指定的容量
  5、关于拷贝,可以把string拷贝成[]byte,不能把[]byte拷贝成string。

相机镜头选择中,35mm还是50mm好,一直犹豫不决?切身体会回答您的问题一首先介绍我的器材,我是佳能,具备142。8351。4501。8851。2四只定焦镜头。二体会,351。4和851。2是我拍摄过程使用率最高的。我没女模拍,也不天音控股国际化战略布局继续推进今年是一带一路倡议提出的第八年。近日召开的第三次一带一路建设座谈会,以通为关键字,强调政策沟通设施联通贸易畅通资金融通民心相通,继续探索促进共同发展的新路子,追求实现同共建国家互利三星在美国进行6G测试,多国抢进6G赛道电子发烧友网报道(文李弯弯)据外媒报道,三星正在美国进行6G(第六代移动通信)的测试试验。而韩国的另外一家公司LG电子在今年8月也成功进行了6G太赫兹频段的无线信号传输测试。如此看明年交车,下周回国,没想到贾跃亭给美国人也深深的上了一课文芝士驾道原创宁城相信很多人最近肯定看到了一则消息,那就是贾跃亭的法拉第未来收到了美国纳斯达克的退市警告。可能对于其他公司,很多人会对这则消息感到惊讶,但是对于贾老板的公司,很多人南非新的重度突变变种冠状病毒B。1。1。529引起关注人们越来越担心一种新的冠状病毒变种。最新的版本是迄今为止发现的突变最严重的版本它有很长的突变列表,一位科学家将其描述为可怕的,而另一位科学家则告诉我这是他们见过的最糟糕的变种。现在假如1万个现代人啥都不带,回到100万年前,多久能造出手机?一百万年以后能活着就不错了,要啥自行车啊捂脸这1万人,只需有500个光学家,500个化学家,500个机械学家,500个电子学家,500个冶金学家,500个算命的,7000个各个专业俄罗斯对谷歌再开罚单因其一直未删除违禁内容据路透社莫斯科11月29日报道,莫斯科一家法庭对字母表公司旗下谷歌公司开出300万卢布(约合4万美元本网注)罚单,原因是该公司未删除法庭认为非法的内容。这是俄罗斯与这个美国科技巨头首例光学导航机器人辅助全口无牙颌手术完成近日,全球首例光学导航机器人辅助全口无牙颌种植及数字化即刻修复手术在北京完成。借助机器人的力传感功能随动功能及光学跟踪定位系统等多项前沿技术,中华口腔医学会口腔种植专业委员会主任委成长型企业如何把握数字化转型机遇?随着大数据移动互联云计算5G人工智能区块链等新一代信息技术与产业的深度融合,数字化产业经济在我国国民经济中起到了重要的支撑重用。中小企业作为我国市场主体的主要组成部分,在稳就业促发陈文玲未来10年全球数字经济渗透率将超过30从历史上看,往往是思想革命先于科技革命,科技革命先于产业革命,产业革命先于经济全球化。思想革命上百年甚至几百年爆发一次,科技革命大部分是60年至80年爆发一次,产业革命是40年至5(独家)频频篡改同行数据,欠缴员工社保涉嫌违法,小影科技带病闯关本文来源时代商学院作者吴桐时代商学院特约研究员吴桐随着短视频火爆,围绕产业链服务上下游的服务商快速崛起,各式各样的剪辑软件应运而生。杭州小影创新科技股份有限公司(以下简称小影科技)
手机直播录视频绝配雷蛇魔音海妖BT无线麦克风大家好,我是波导终结者。现在手机拍视频或者直播越来越普遍,胜在小巧便携移动性好,然而想要好一点的收音效果,却又需要专业的麦克风。有线麦克风的话,会影响手机的便携性,容易勾到线,也有双芯拍摄人像有多给力?与iPhone13对比,看出国产手机真实水平现在有些手机的自拍镜头,人像拍摄都能够呈现出最真实的一面,而且人物妆容和整体型态也更贴近于自然。比如苹果的iPhone手机在自拍方面都强调真实,甚至成为自拍达人的首选。不过,在对比苹果以旧换新大放血,iPhone最高折抵5400元众所周知,iPhone恐怕是业界既好用又保值的手机之一,甚至一度还有钉子户的说法。但对苹果来说,钉子户的现象对苹果无疑是不利的。官方为了吸引更多用户购买苹果新品,营销手段也非常丰富安徽积极探索以工业互联网助ampampquot科技之花ampampquot结出ampampquot产业之果ampampquot技术供需衔接工业互联网促匹配企业生产中遇到技术难题,如何解决?不久前,国内一家知名家电企业在柠檬豆皖豆云工业互联网平台上发布内胆自动清洁等10余项技术需求。平台快速匹配科研资源为企银行加快布局外贸小微企业服务,金融科技赋能搭建结算系统21世纪经济报道记者陈植上海报道如何服务好外贸小微企业,还真是一个问题。一家城商行对公业务部门主管向记者直言。去年以来,他一直在探索升级现有的外贸收付款系统,将后者服务覆盖面扩展到小赢科技Q1财报赋能小微企业新市民业务金融科技成为亮眼名片金融界北京时间2022年5月24日,中国领先的金融科技公司小赢科技发布了截至2022年3月31日第一季度未经审计的财务报告。财报数据显示,2022年一季度,小赢科技业务规模和业绩指我国科技人才政策十年发展与面向高水平科技自立自强的优化思路中国网中国发展门户网讯党的十八大以来,党中央国务院及有关部门陆续推出了覆盖人才教育与培养人才使用与发展人才评价与激励等方面的科技人才政策,体系不断健全,成效日益显著。当今世界正经历吊挂双面显示数字标牌吊装双面屏吊挂双面电子显示屏产品简介吊挂双面显示数字标牌使用ALLINGlass设计,将2片面板嵌入高透钢化玻璃内部。系统支持Android系统或windows系统,超薄玻璃外壳,任何可视角度观看无色彩的失真重核心素养育数字人才来源中国教育新闻网随着科学技术的进步,尤其是信息科技的进步,数字素养与技能成为社会主义事业建设者的一种必备素养和技能,学校需要成为数字素养教育和信息科技课程的主阵地。如果把以前选修从会上云到用好云,数字化转型这样提速目前,越来越多企业意识到数字化转型的重要性,并不断加快数字化改造步伐。不过,对于企业来说,业务上云只是第一步,如何用技术手段把云管好用好,则有着更加丰富的内涵。云原生时代,容器Ku加快智能汽车操作系统的开发和安全认证智能汽车将是未来汽车发展的一个大方向,未来面向智能交通的智能汽车,将会有强大的定位能力,道路识别能力,智能交通的控制能力,车况管理能力,计费体系。这样的智能汽车会安装各种位置识别的