Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
スライス容量拡張量がどのように決まるのか追った / 180709 LT
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
kaznishi
July 09, 2018
Programming
190
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
スライス容量拡張量がどのように決まるのか追った / 180709 LT
kaznishi
July 09, 2018
More Decks by kaznishi
See All by kaznishi
Finally_I_can_kichijojipm32
kaznishi
0
720
バッチ処理と冪等性 / 20191218_merpay_techtalk
kaznishi
3
5.7k
Bounds Check Eliminationについて調べてみた / 1218-lt
kaznishi
0
600
Hello, Prometheus!! Goで作るexporter自作入門 / 180727 LT
kaznishi
6
3.9k
Goのスライス容量拡張量がどのように決まるのか追った / 180713 LT
kaznishi
3
3.8k
Other Decks in Programming
See All in Programming
IBM Bob Dojo #1 仕様駆動開発入門
oniak3ibm
PRO
0
350
テストを司るデーモンに会いに行く 〜隔離した仮想マシンでテストを通すまで〜
h1d3mun3
1
620
ゲームコントローラやキーボードのファームウェアをSwiftで書く
kishikawakatsumi
1
280
KiroのSpecで「五目並べ」を作ってみる
satoshi256kbyte
1
350
難しいけど、読めた。- OSSの入口に立った話。
sts11142
0
140
[2026-09-26]空論ジェネリックプロセス~テスト資産とAIで紡ぐ、再現可能なパフォーマンスチューニングの話~
tosite
0
250
AI Agent時代のリアーキテクチャ戦略と実践
hokaccha
9
5.4k
WebRTC映像をAirPlayに対応させる挑戦.pdf
monolithic_adam
0
340
Atomic Design, Enforced: Scaling Mobile Design Systems (next.app devCon / droidCon Berlin 2026)
steliosf
PRO
0
120
FreeBSDでZabbixを動かす
kenkino
0
360
プロダクトコードからライブラリの境界を見つける
elmetal
PRO
0
100
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
5
4.9k
Featured
See All Featured
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.4k
Writing Fast Ruby
sferik
630
63k
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
730
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.4k
The Pragmatic Product Professional
lauravandoore
37
7.5k
New Earth Scene 8
popppiees
4
2.6k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
8k
YesSQL, Process and Tooling at Scale
rocio
174
15k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
Navigating Weather and Climate Data
rabernat
0
550
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
74
42k
A Soul's Torment
seathinner
8
3.7k
Transcript
※(7/13追記)ブラッシュアップした内容で2018/7/13 のgolang.tokyoでLTしてきたので、そちらのスライド の方をご覧ください! https://speakerdeck.com/kaznishi/180713-lt
スライス容量拡張量が どのように決まるのか追った 2018-07-09 Gopher道場 #2 LT大会 by kaznishi
自己紹介 twitter: @kaznishi1246 サーバーサイド,インフラ PHP, Scala Go歴はほぼ1ヶ月(≒Gopher道場期間)
今回のテーマ
スライスの容量がいっぱいの ときにappendで追加される容 量の話
復習 スライスは配列の部分列への参照のためのデータ 構造 配列は固定長 容量が足りなくなった場合、容量が拡張された新 たな配列が作られ、参照先が切り替わる
容量の拡張量は?
容量の拡張量は? 「プログラミング言語Go」より 「Goならわかるシステムプログラミング」より 拡張ごとに配列の大きさを倍にすることにより過 剰な回数の割り当てを避け、一つの要素の追加が 平均的に定数時間で済むことを保証しています。 “ “ もし、余裕がない状態でappend()を呼ぶと、cap() の2倍のメモリを確保し、今までの要素をコピー
したうえで新しい要素を新しいメモリ領域に追加 します。 “ “
確かめてみよう
Go Playgroundで確認 cap = 4 のとき https://play.golang.org/p/zPLWMUM2gzw OK
Go Playgroundで確認 cap = 5 のとき https://play.golang.org/p/eyPOVocDUc- 「12」!!!???
はて
goの実装を追ってみた
https://github.com/golang/go/blob/master/src/runti me/slice.go func growslice(et *_type, old slice, cap int) slice
{ ~略~ newcap := old.cap doublecap := newcap + newcap if cap > doublecap { newcap = cap } else { if old.len < 1024 { newcap = doublecap } else { // Check 0 < newcap to detect overflow // and prevent an infinite loop. for 0 < newcap && newcap < cap { newcap += newcap / 4 } ~略~
~略~ 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): var shift uintptr if sys.PtrSize == 8 {
// Mask shift for better code generation. shift = uintptr(sys.Ctz64(uint64(et.size))) & } else { shift = uintptr(sys.Ctz32(uint32(et.size))) & } 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 = roundupsize(uintptr(newcap) * et.size) overflow = uintptr(newcap) > maxSliceCap(et.size) newcap = int(capmem / et.size) }
newcapに調整がかかってる
switch { case et.size == sys.PtrSize: ~略~ capmem = roundupsize(uintptr(newcap)
* sys.PtrSize) ~略~ newcap = int(capmem / sys.PtrSize) default: ~略~ capmem = roundupsize(uintptr(newcap) * et.size) ~略~ newcap = int(capmem / et.size) } 確保メモリ = roundupsize(補正前スライス容量 x 要素サイズ) 補正後スライス容量 = 確保メモリ / 要素サイズ
roundupsize?
https://github.com/golang/go/blob/master/src/runti me/msize.go func roundupsize(size uintptr) uintptr { if size <
_MaxSmallSize { if size <= smallSizeMax-8 { return uintptr(class_to_size[size_to_class8 [(size+smallSizeDiv-1)/smallSizeDiv]]) } else { return uintptr(class_to_size[size_to_class128 [(size-smallSizeMax+largeSizeDiv-1)/largeSizeDiv]]) } } if size+_PageSize < size { return size } return round(size, _PageSize) }
roundupsizeというからにはキリの良いところまで メモリの確保量を切り上げているのだろうが、何 のための切り上げ? class_to_size , size_to_class の'class'とは?
https://github.com/golang/go/blob/master/src/runti me/sizeclasses.go なんだろうこれは、という感じ
「Goならわかるシステムプログラミング」より 小さなオブジェクトについては、より小さな単位 の「クラス」という分類で空きメモリのリストを 持っています。クラスからのメモリ取得では、リ クエストされたサイズに近いクラスの空きリスト があればそこからメモリを確保します。この場合 にはロックが不要であり、それだけ高速に処理で きます。 “ “
クラスという分類で空きメモ リリストを管理するため、キ リの良いところまで切り上げ をしている
意味が掴めたところでnewcapの計算 結果を確かめてみる
再掲
old.cap = 5 Go Playground環境においてはintのet.sizeは4, sys.PtrSizeも4 newcap := old.cap doublecap
:= newcap + newcap ~略~ if old.len < 1024 { newcap = doublecap } else { ~略~ case et.size == sys.PtrSize: ~略~ capmem = roundupsize(uintptr(newcap) * sys.PtrSize) ~略~ newcap = int(capmem / sys.PtrSize)
計算してみたところ、ちゃんと結果が12になりまし た。 https://play.golang.org/p/oSn8GbSWVkK
まとめ スライスの容量拡張される際の新容量は、元容量 の大体2倍である。 (今回の話から省いたが、スラ イス長が大きい場合(1024が閾値)は大体1.25倍) きっちり2倍にならないのは、メモリ管理上キリの よいところまでメモリ確保量が切り上げされてい るからである。
None