go string 實現

在go中string是不可變的,這意味著對string發生改變的操作實際上都是通過分配新的string去實現的

在string內存分配上,對于小對象分配到棧,大對象分配到堆中

string在go中的結構其實很簡單,就是一個指向實際數據的指針以及字符串的長度。

type stringStruct struct {str unsafe.Pointerlen int
}

創建

先創建string Struct,然后轉換為string

以字符指針為字符串指針,到第一個null byte偏移量為長度

func gostringnocopy(str *byte) string {ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}s := *(*string)(unsafe.Pointer(&ss))return s
}

找到第一個非null byte的位置

func findnull(s *byte) int {// 若指針為nil,則返回0if s == nil {return 0}// Avoid IndexByteString on Plan 9 because it uses SSE instructions// on x86 machines, and those are classified as floating point instructions,// which are illegal in a note handler.// 對于plan9系統,IndexByteString是非法的// 因此需要轉換為字符數組,遍歷直到發現null byteif GOOS == "plan9" {p := (*[maxAlloc/2 - 1]byte)(unsafe.Pointer(s))l := 0for p[l] != 0 {l++}return l}// 最小頁大小const pageSize = 4096offset := 0ptr := unsafe.Pointer(s)// IndexByteString uses wide reads, so we need to be careful// with page boundaries. Call IndexByteString on// [ptr, endOfPage) interval.// 計算到達下頁剩余的byte數量safeLen := int(pageSize - uintptr(ptr)%pageSize)for {// 以本頁剩余byte數量為長度,指針為字符數組轉換為stringt := *(*string)(unsafe.Pointer(&stringStruct{ptr, safeLen}))// 嘗試找到本頁字符串中的null byte位置,如果找到,返回之前遍歷過的偏移量加找到的位置if i := bytealg.IndexByteString(t, 0); i != -1 {return offset + i}// 移動指針到下頁ptr = unsafe.Pointer(uintptr(ptr) + uintptr(safeLen))// 更新偏移量和剩余byte數量為頁大小offset += safeLensafeLen = pageSize}
}

指定大小進行創建string

func rawstring(size int) (s string, b []byte) {// 分配指定大小的字符數組。// 小對象分配到每個p cache的空閑list,大對象(>32kB)分配到堆中p := mallocgc(uintptr(size), nil, false)// 轉換為指定大小string和字符數組return unsafe.String((*byte)(p), size), unsafe.Slice((*byte)(p), size)
}

C string轉換為Go string

func gostring(p *byte) string {// 找到字符串長度l := findnull(p)if l == 0 {return ""}// 分配對應長度的strings, b := rawstring(l)// 復制字符指針的內容到新分配的stringmemmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l))return s
}

拼接

在緩存能承載拼接字符串時,直接用緩存去儲存拼接字符串。這能防止頻繁的堆分配,并減少額外的gc開銷

緩存不行才會重新分配內存

// concatstrings implements a Go string concatenation x+y+z+...
// The operands are passed in the slice a.
// If buf != nil, the compiler has determined that the result does not
// escape the calling function, so the string data can be stored in buf
// if small enough.
func concatstrings(buf *tmpBuf, a []string) string {idx := 0l := 0count := 0for i, x := range a {// 判斷拼接字符串長度是否合法n := len(x)if n == 0 {continue}if l+n < l {throw("string concatenation too long")}// 遞增總字符串長度l += n// 遞增非空字符串數量count++// 記錄最后非空字符串索引idx = i}// 如果非空字符串數量為0,則返回空if count == 0 {return ""}// If there is just one string and either it is not on the stack// or our result does not escape the calling frame (buf != nil),// then we can return that string directly.// 如果僅有一個非空字符串,并且它不需要轉義當前幀(buf != nil)或者它不在棧上(!stringDataOnStack(a[idx])),則直接返回該字符串if count == 1 && (buf != nil || !stringDataOnStack(a[idx])) {return a[idx]}// 分配總字符串長度的string,并將拼接字符串復制到新string的字符數組中s, b := rawstringtmp(buf, l)for _, x := range a {copy(b, x)b = b[len(x):]}return s
}func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {if buf != nil && l <= len(buf) {b = buf[:l]s = slicebytetostringtmp(&b[0], len(b))} else {s, b = rawstring(l)}return
}// stringDataOnStack reports whether the string's data is
// stored on the current goroutine's stack.
func stringDataOnStack(s string) bool {ptr := uintptr(unsafe.Pointer(unsafe.StringData(s)))stk := getg().stackreturn stk.lo <= ptr && ptr < stk.hi
}

string常見實現方式對比

eager copy

在每次拷貝時將原string對應內容以及所持有的動態資源完整復制

優點

  • 實現簡單
  • string互相獨立,不會相互影響

缺點

  • 字符串較大時,比較浪費空間
copy on write

寫時復制只有在string需要對對象進行修改時才會執行復制

在實現中,需要記錄string引用的數量refCount,每當string被引用一次,refCount++。而當需要對string做修改時,則重新申請空間并復制原字符串,refCount–。最終當refCount為0時回收內存

優點

  • 字符串空間較大時,減少了分配、復制字符串時間和空間

缺點

  • 記錄string引用的數量需要原子操作,帶來性能損耗
  • 在某些情況下反而會帶來額外開銷。比如線程1訪問字符串A,線程2訪問字符串B,字符串A、B共享同一片內容,當線程1、2都修改同一片字符串,就會都進行兩次復制,外加最開始的分配和最后的內存釋放,這比eager copy的兩次內存分配的代價更高
Small String Optimization

基于字符串大多數較短的特性,利用string本身的棧空間來儲存短字符串;當字符串長度大于臨界點時,則使用eager copy

優點

  • 短字符串時,無動態內存分配

缺點

  • string對象占用空間更大

Ref

  1. https://www.cnblogs.com/promise6522/archive/2012/03/22/2412686.html
  2. https://www.zhihu.com/question/54664311/answer/1978680475

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/14600.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/14600.shtml
英文地址,請注明出處:http://en.pswp.cn/web/14600.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

用于與 HTTP 服務器通信的函數

用于與 HTTP 服務器通信的函數 Plant Simulation 提供了許多使用 HTTP 協議與 HTTP 服務器通信的函數。可使用這些函數來發送 HTTP 請求、發送數據和從 HTTP 響應中接收數據&#xff0c;以及在 HTTP 服務器上創建和刪除資源&#xff1a; httpGetRequest 發送 GET 請求。請求…

在 Visual Studio 2022 (VS2022) 中刪除 Git 分支的步驟如下

git branch -r PS \MauiApp1> git push origin --delete “20240523備份” git push origin --delete “20240523備份”

PCL 常用小知識

文章目錄 一、時間計算二、實現類似`pcl::PointCloud::Ptr`和`pcl::PointCloud`的兩個類相互轉換三、查找點云的x,y,z的極值四、知道需要保存點的索引,從原點云中拷貝點到新點云五、從點云里刪除和添加點六、對點云進行全局或局部變換七、鏈接兩個點云字段(兩點云大小必須相…

若依 ruoyi-vue 用戶賬號前后端參數校驗密碼 手機號 郵箱

前端 <el-dialog :title"title" :visible.sync"open" width"800px" append-to-body><el-form ref"form" :model"form" :rules"rules" label-width"120px"><el-row><el-col :span…

Vue3骨架屏(Skeleton)

效果如下圖&#xff1a;在線預覽 APIs 參數說明類型默認值必傳animated是否展示動畫效果booleantruefalsebutton是否使用按鈕占位圖boolean | SkeletonButtonPropsfalsefalseavatar是否顯示頭像占位圖boolean | SkeletonAvatarPropsfalsefalseinput是否使用輸入框占位圖boolea…

SOLIDWORKS二次開發服務商 慧德敏學

SOLIDWORKS是一套三維設計軟件, 采用特征建模、變量化驅動可方便地實現三維建模、裝配和生成工程圖。SOLIDWORKS軟件本身所具有的交互方式, 可以使用戶對已生成模型的尺寸、幾何輪廓和相互約束關系隨時進行修改, 而不需要編程。但要實現設計意義上的變量化繪圖和系列化設計, 需…

java-查詢字符串當中是否包含中文

文章目錄 前言java-查詢字符串當中是否包含中文 前言 如果您覺得有用的話&#xff0c;記得給博主點個贊&#xff0c;評論&#xff0c;收藏一鍵三連啊&#xff0c;寫作不易啊^ _ ^。 ??而且聽說點贊的人每天的運氣都不會太差&#xff0c;實在白嫖的話&#xff0c;那歡迎常來啊…

軟考系統架構師一些知識點記錄-1

個人隨筆 (Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu) 引言 準備去參加軟考的考試&#xff0c;但對一些概念掌握的還不夠&#xff0c;借此機會&#xff0c;整理記錄一二&#xff0c;便于自己理解掌握。 知識范圍 感覺不夠清晰的部分主要是第三篇和第四篇的部分。…

國際頂會認可!KaiwuDB 論文入選 ICDE 2024

導 讀 近日&#xff0c;KaiwuDB 與中國人民大學合作的論文 FOSS: A Self-Learned Doctor for Query Optimizer 被數據庫領域頂會The 40th IEEE International Conference on Data Engineering (ICDE 2024) 錄用啦! 論文中提出了具備自學習、自診斷能力的查詢優化器 FOSS&…

USB官方文檔怎么下載

直接登錄USB官網"https://usb.org/" 如&#xff0c;我需要查找與USB device class相關的文檔 點擊搜索后就能找到。 學習還是要以官方文檔為主&#xff0c;博客上的介紹不可信&#xff0c;USB協議規范很重要!

商品發布功能

文章目錄 1.SPU和SKU介紹1.SPU2.SKU3.兩者之間的關系 2.完成商品發布界面1.組件引入1.commoditylaunch.vue 引入到 src/views/modules/commodity下2.multiUpload.vue 引入到 src/components/upload/multiUpload.vue 2.創建菜單1.創建目錄2.創建菜單&#xff0c;注意菜單路由要匹…

go語言中同一for循環體內的多個初始變量和多個自增變量用法示例

在go語言的for循環體中&#xff0c;我們可以同時初始多個變量&#xff0c; 也可以同時多多個變量進行自增/自減操作&#xff0c; 用法如下&#xff1a; for 后面的多個初始化變量使用的是逗號分隔的批量賦值操作&#xff0c;多個變量自增自減使用 加減運算符和逗號分隔 字符…

MySQL之性能剖析和Schema與數據類型優化(一)

性能剖析總結 1.定義性能最有效的方法是響應時間2.如果無法測量就無法有效地優化&#xff0c;所以性能優化工作需要基于高質量、全方位及完整的響應時間測量3.測量的最佳開始點是應用程序&#xff0c;而不是數據庫。即使問題出在底層的數據庫&#xff0c;借助良好的測量也可以…

C++系列-友元

&#x1f308;個人主頁&#xff1a;羽晨同學 &#x1f4ab;個人格言:“成為自己未來的主人~” 我們在之前的文章有提到友元&#xff0c;我們先來看下面的這段包含了友元的代碼&#xff1a; ??#define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace…

CLIP論文學習

學習來自B站bryanyzhu

jdk17安裝教程詳細(jdk17安裝超詳細圖文)

2021年9月14日JDK17 發布&#xff0c;其中不僅包含很多新語言功能&#xff0c;而且與舊版 JDK 相比&#xff0c;性能提升也非常明顯。與之前 LTS 版本的 JDK 8 和 JDK 11 相比&#xff0c;JDK17 的性能提升尤為明顯&#xff0c;本文將教你如何安裝 相比于JDK1.8&#xff0c;JD…

虛擬機網絡設置為橋接模式后未顯示網絡

本方法為&#xff0c;VMware配置正確&#xff0c;但在嘗試其他辦法后未能成功解決的人提供一種方法 本機的虛擬機使用NAT模式正常使用 但是使用橋接模式后重啟&#xff0c;未發現虛擬機內網絡設置,詳見下圖&#xff1a; 使用 ifconfig 查看網絡詳情 發現沒有ens33接口 查看硬…

雙非本科,逆襲中大廠的 Java 學習路線

從零基礎入門 Java&#xff0c;到最后秋招上岸&#xff0c;筆者也是花費了不少的經歷&#xff0c;也走了很多彎路。這一篇文章會記錄下真正有用的學習路線。 為什么要強調真正有用&#xff1f;網上的很多所謂從入門到求職&#xff0c;推薦的路線都超級長&#xff0c;零基礎的同…

LeetCode198:打家劫舍

題目描述 你是一個專業的小偷&#xff0c;計劃偷竊沿街的房屋。每間房內都藏有一定的現金&#xff0c;影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統&#xff0c;如果兩間相鄰的房屋在同一晚上被小偷闖入&#xff0c;系統會自動報警。 給定一個代表每個房屋存…

【學習筆記】Windows GDI繪圖(六)圖形路徑GraphicsPath詳解(中)

上一篇【學習筆記】Windows GDI繪圖(五)圖形路徑GraphicsPath詳解(上)介紹了GraphicsPath類的構造函數、屬性和方法AddArc添加橢圓弧、AddBezier添加貝賽爾曲線、AddClosedCurve添加封閉基數樣條曲線、AddCurve添加開放基數樣條曲線、基數樣條如何轉Bezier、AddEllipse添加橢圓…