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
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
730
バッチ処理と冪等性 / 20191218_merpay_techtalk
kaznishi
3
5.7k
Bounds Check Eliminationについて調べてみた / 1218-lt
kaznishi
0
610
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
Herb in Rails 8.2: Your ERB views, now HTML-aware @ Kaigi on Rails 2026, Tokyo, Japan
marcoroth
2
360
AI時代のシニアエンジニアとは
yosuke_furukawa
PRO
12
10k
作れる、でも消せるか?──安全に「枯らして消す」機能削除術 / Drain, Then Delete
chobishiba
2
1.2k
AIが生成したコードは読むべきか?抽象化設計とコードの品質保証 / abstraction-design-and-quality
minodriven
11
6.8k
ChromeでローカルLLM
ryu1013
0
170
APNsからLive Activityを開始する話
yumnumm
0
180
golang-bob.pdf
iwatsukayura
0
140
When benchmarks go bad - what I learned from measuring performance wrong
hollycummins
0
240
最近”作らせてる” ローカルAIアプリの話
akit37
0
500
Next.js: The final boss of Web Performance
guaca
0
350
Optunaを作ったときにやりたかったこと、その後 (2026/10/16, Optuna Meetup #3)
iwiwi
4
1.3k
[JA] Domain Modeling with Vanilla Rails: 「操作」から再考するRailsの設計論
yasaichi
4
1.1k
Featured
See All Featured
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
610
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
330
Utilizing Notion as your number one productivity tool
mfonobong
4
630
Making Projects Easy
brettharned
120
6.8k
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
600
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.8k
Documentation Writing (for coders)
carmenintech
77
5.6k
Designing Experiences People Love
moore
143
24k
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
1
580
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
900
The Cult of Friendly URLs
andyhume
79
7k
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
380
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