C# ボックス化
あいさつ
どうも、はかせです。
最近ILの勉強をしていて
ようやくC#という言語が
それとなくわかってきたような気がしなくもない感じです。
(要はC#ナンモワカランです)
ただ私自身個人や趣味でゲーム開発を行う際使うツールは
Unityですし、おそらく就職先の企業でもC#を触る機会はあると思います。
なので完全理解とまでいかなくても
C#をある程度エクストリームに使いこなし
パフォーマンスを出せるようになってみたいわけです。
ということで今回は色々C#のパフォーマンス系の記事とかで
見かけるボックス化についてまとめていきたいと思います。
ボックス化とは?
極めてざっくり言うと、
値型→参照型の変換をすることです。
なんでそんなことするのかというと、
大昔のJavaとか.NETの配列はプリミティブ型(要は値型)が無理だったらしく、
それでも配列で扱いたいっていうニーズがあり
一旦参照型でラップして扱うっていう解決策を取ったからだそうです。
※追記 2019/09/16
配列は値型大丈夫だったそうですが、
その他のコレクション(Listとか)が無理だったそうです。
ちなみに今ではジェネリクスとかできてそんな必要性は消滅したっぽいです。
ボックス化は悪?
値型だろうが参照型だろうが一緒くたに扱えるんで
使い勝手やわかりやすさには貢献すると思います。
ただパフォーマンス的な観点から見たら
絶対悪に等しいのかなと思っています。
値型ってのはスタック領域に置かれ、
参照型はヒープ領域に置かれます。
一般的にスタック領域の確保の方がヒープ領域の確保より高速です。
Unityでもなんでもいいですけど開発をしていて、
適当にnewしまくるとすぐフレーム落ちしますよね。
ただ適当にintとか宣言しまくってもそうそうフレーム落ちしないですよね。
つまりはそういうことです。
つまり値型で済むものを参照型にしたせいで
確保するメモリ領域もスタック領域からヒープ領域へと
変わってしまいパフォーマンスが落ちるということですね。
今どきの言語でボックス化って起こってるん?
ぶっちゃけ意識してないだけで結構起こってます。
例えばみんな大好きEqual関数はこんな感じです。
public override bool Equals(object obj);
結構色々なクラスやライブラリの中でしれっと使われているこいつ。
引数がobject型になっていますね。
実はobject型って参照型です。
つまりEquals関数の引数にintやdoubleを放り込んだ瞬間ボックス化発生です。
まぁ 10.Equals(100) みたいな感じの値型どうしのものなら
それ用のオーバーロードが用意されてるんでいいんですけど、
"Hoge".Equals(110) みたいなのだともうダメです。事件発生です。
こんな感じのobjectから生えてるメソッドは
結構object型で受け取るので
知らず知らずのうちにボックス化起こってます。
あとUnityで開発してると良く使うVector3とか。
この辺もボックス化しないよう==はオーバーライドしてるみたいですが、
Equalsは何も手を付けてません。
つまりListとかに放り込んでLINQとかで
ごにょろうとした瞬間ボックス化です。
※追記 2019/09/16
2018.2以降のVector3はIEquatable
ボックス化は起きないみたいです。
github.com
ボックス化回避はできるの?
ぶっちゃけ値型→参照型みたいな変換が起こらないよう
自前で比較処理とか書けば解決です。
確かUniRxとかもVector3用のEquals関数書いて
ボックス化回避してたはずです。
どんな感じで書けばいいかって言うと
//これはさっきも言った通りボックス化する public override bool Equals(object obj); //こうすれば最初っからintだからボックス化しない public override bool Equals(int obj);
要はobject型で受け取るなってことですね。
あとは変数の宣言とか受け取り方
//しれっとint→object変換が走る object obj = 10; //intで宣言しとけばよし int obj = 10; //varは所詮型推論だから変換は走らない var obj = 10;
object型ってC++のvoid*みたいで楽でいいんですけどねー
パフォーマンス的には邪魔な子みたいです。
あとがき
今回はボックス化についてでした。
私も元からぼんやり理屈はわかってたんですが、
実際どうなんってのはよくわかってなかったので
今回調べてまとめてみました。
(色んなことを雰囲気で片づけて進めてきた人←)
ボックス化とかメモリリークとかって
太古の昔の存在みたく感じますけど、
今でもまだお隣さんにいるっぽいですよ。
それでは今回はこの辺でノシ