Home
Blog
Company
TechMemo
Contact
メニュー
スタッフブログ
会社案内
技術系備忘録
お問い合わせ
旧ホームページ
ブログ更新履歴
2024/03/11
rlib-MML 機能追加しました
2023/12/16
rlib-MML アプリ ver1.0.6 公開しました
2023/11/13
rlib-MML 機能追加しました
2023/01/06
rlib-MML アプリ ver1.0.5 公開しました
2021/12/01
rlib-MML アプリ 更新しました
コンテンツ更新履歴
最新の30件
2024-04-13
技術系備忘録/Docker/Emscripten
2022-10-24
技術系備忘録/Windows/接続されているモニタ以上の解像度でデスクトップ表示
2021-10-14
技術系備忘録/C++/小技/無名関数の再帰をローテクで
2021-08-10
技術系備忘録/C++/小技
2021-08-08
技術系備忘録/C++/小技/型で条件分岐
2021-06-10
技術系備忘録/Docker/サーバー死活監視スクリプト
2021-03-29
技術系備忘録/C++/Boost/boost.formatを使った文字列フォーマット。printf系関数を置き換え
2020-10-21
技術系備忘録/VMware/Ubuntu8.10にVMwareServer1.0をインストール
2020-10-14
技術系備忘録/VMware
技術系備忘録/VMware/CentOS7にVMwarePlayer12をインストール
2020-06-03
技術系備忘録/TypeScript/二分探索(binary search)
2020-06-01
技術系備忘録/Docker/SSLアクセラレータ&リバースプロキシ
2019-11-08
技術系備忘録/C++/OpenSSL/ビルド方法
2019-11-04
技術系備忘録/C++/VisualStudio/MSBuild.exeのパスを解決して実行
2019-10-02
MenuBar
2019-09-05
技術系備忘録/Docker
2019-09-04
技術系備忘録/Docker/LAMP環境構築
2019-07-16
会社案内/品質管理方針
2019-04-18
技術系備忘録/AWS/SoftEtherを使ってVPN接続
2019-02-18
技術系備忘録/C++/小技/std.set map系の比較関数の新機能
2018-05-25
技術系備忘録/データベース
技術系備忘録/データベース/SQLite
技術系備忘録/データベース/SQLite/WHERE IN で複数指定するクエリ
2018-05-20
会社案内/求人情報
2018-01-11
技術系備忘録/AWS/EC2 AmazonLinuxにSWAPを設定
技術系備忘録/AWS
2017-11-21
技術系備忘録/C++/Boost/インストール手順
2017-10-25
技術系備忘録/C++/Boost
技術系備忘録/C++/VisualStudio
技術系備忘録/C++/Boost/boost.asioコルーチン内で表コンテキストの処理を行う
リンク
rlib-MML デモページ
MML (Music Macro Language) をコンパイルし、再生や標準MIDIファイル出力をブラウザ上で行える形にまとめています。
Magome
クラウドベースのMIDIシーケンサ
音楽制作に興味のある方を対象に、スタンドアロンでも使え、ネットならではの面白さも兼ね備えた音楽制作アプリの提供を目指しています。
twitter
Tweets by thinkridge
(有)シンクリッジは 技術者 を募集しております。
|
一覧
検索
最新
ヘルプ
ページへ戻る
履歴
印刷
技術系備忘録/C++/最適化小手先テクニック/ビットフィールドを活用すべし(メモリ節約編)
のソース
xpwiki
:
技術系備忘録
/
C++
/
最適化小手先テクニック
/
ビットフィールドを活用すべし(メモリ節約編)
のソース
差分
を表示
技術系備忘録/C++/最適化小手先テクニック/ビットフィールドを活用すべし(メモリ節約編)
へ行く。
例えば、文庫本を管理するソフトウェアを作るとします。 各文庫本にはジャンル情報があり、ジャンルは複数個持つことが可能とします。 何も考えずに組むと List1 のようなクラスになると思います。 -List1 #prettify{{ class CBook // 文庫本クラス { public: string m_sTitle; // タイトル // ジャンルフラグ int m_nGenreScienceFiction; // SF (true or false) int m_nGenreLoveStory; // 恋愛 (true or false) int m_nGenreMystery; // ミステリー (true or false) int m_nGenreHorror; // ホラー (true or false) int m_nGenreComedy; // コメディ (true or false) int m_nGenreShort; // 短編 (true or false ) }; }} /* Windowsプログラムでは"int"を使わずに"BOOL"と書くことがあると思いますが、 "BOOL"は"int"の別名と定義されてますので、ここでは同じ意味と思って下さい。 */ ここでは、タイトル(m_sTitle)は置いといて、ジャンル情報に着目します。 ジャンル情報を見ると、各項目はフラグ(true or false)として使用するのですが、型はintを使っています。 それが6種類あるので、使用するメモリは、4Byte×6で24Byteです。 文庫本が数冊であれば問題ない量ですが、数十万冊などもあり得えることを考慮すると、なるべく無駄遣いは避けたいとこです。 少し工夫して、int ではなく bool を使うようにしたものが List2 です。 -List2 #prettify{{ class CBook // 文庫本クラス { public: string m_sTitle; // タイトル // ジャンルフラグ bool m_bGenreScienceFiction; // SF (true or false) bool m_bGenreLoveStory; // 恋愛 (true or false) bool m_bGenreMystery; // ミステリー (true or false) bool m_bGenreHorror; // ホラー (true or false) bool m_bGenreComedy; // コメディ (true or false) bool m_bGenreShort; // 短編 (true or false) }; }} こうすることで、24Byteだったのが 6Byte に収まりました。(boolは1byteとしています) これで十分かもしれませんが、もっと節約したい場合もあると思います。 ビットフィールドを使うと以下のようになります。 -List3 #prettify{{ class CBook // 文庫本クラス { public: string m_sTitle; // タイトル union{ // ジャンルフラグ struct{ char bScienceFiction : 1; // SF (true or false) char bLoveStory : 1; // 恋愛 (true or false) char bMystery : 1; // ミステリー (true or false) char bHorror : 1; // ホラー (true or false) char bComedy : 1; // コメディ (true or false) char bShort : 1; // 短編 (true or false) }; char All; }m_Genre; }; }} こうするとジャンル情報は1byteで収まります。 さらに、例では6ジャンルしか定義してませんが、8ジャンルまでなら1byteで済みます。 以上、ビットフィールドの活用方法としては一番単純な例ですが、メモリ節約の面からの効果が期待出来ます。 なお、C(C++)言語の通説として、「コンピュータにとってはintが一番扱いやすく処理も軽い」とありますが、これはCPUの内部処理のことです。この例で int を使うことで軽くなるのは、ビット処理がint処理で済むその瞬間のみです。 実際の運用では、この場合はCBookを構築、比較、コピーなどの処理を考慮すると、少ないメモリ処理量で済ませられる効果が大きいと思います。 特に昨今のコンピュータは、メモリはCPUより遅いクロックで動作しており、メモリアクセスを少なくすること(=メモリを節約すること)が、CPUの待ち時間を減らし、キャッシュヒット率を上げることに貢献します(と聞いています)。 /* 余談ですが、Pentium3とかが出始めた頃、ちょっと時間のかかる計算式を、リアルタイムに計算するのではなく、計算結果を予めメモリに用意しておき、テーブル参照だけで答えが出るような処理にしたら逆に遅くなってしまったことがあり、メモリ参照というのは思った以上に重い処理になりつつあるというのを実感しました。 */ ちなみに、ビットフィールドを使用しないで同じことをやる例として、List4 のようなものがあります。 -list4 #prettify{{ #define SCIENCEFICTION 0x1 // SF #define LOVESTORY 0x2 // 恋愛 #define MYSTERY 0x4 // ミステリー #define HORROR 0x8 // ホラー #define COMEDY 0x10 // コメディ #define SHORT 0x20 // 短編 class CBook // 文庫本クラス { public: string m_sTitle; // タイトル char m_cGenre; // ジャンルフラグ }; }} このような記述は古いソフトウェアで良く見かけます。 数値型変数のビット管理をプログラマが自分で行うやり方です。 自分の場合(この例では)ビットフィールドを使うと思いますが、最適化の観点からみると、この記述で非効率となる要因は特に思いつきません。 逆に、コンパイラ任せにしないという意味から言えば、効率的な記述と言えるのかもしれません。 なお、ビットフィールドは 1BIT 単位でしか使えないものではありません。 例えば、CBook クラスに、本のサイズという項目を設けた場合は List5 のように記述出来ます。 -List5 #prettify{{ class CBook // 文庫本クラス { public: string m_sTitle; // タイトル union{ // フラグ struct{ // ジャンルフラグ char bScienceFiction : 1; // SF (true or false) char bLoveStory : 1; // 恋愛 (true or false) char bMystery : 1; // ミステリー (true or false) char bHorror : 1; // ホラー (true or false) char bComedy : 1; // コメディ (true or false) char bShort : 1; // 短編 (true or false) // 本のサイズ char nSize : 2; // 0=A3以上 1=A4 2=A5 3=A6 }; char All; }m_Property; }; }} このように、記述することが可能です。 面倒なビット演算はコンパイラが面倒みてくれますので、nSize は普通の変数のように扱えます。 - #prettify{{ if( m_Book.m_Property.nSize == 2 ){ // A5サイズなら }} みたいな記述も可能です。 (ただ、内部的にはビット演算処理を行うコードが出力されてますので、処理速度について注意が必要です。) こうなると List4 にある #define を使って自前で処理をコーディングすることはかなり面倒になりますので、ビットフィールドのメリットが現れてきます。 以上、今回のネタはメモリ節約という最適化の一つのネタとして挙げてみました。 ただ、メモリ節約と処理速度との関係は難しく、メモリ節約することで動作が遅くなることもあれば早くなることもあり得ますので、一概にこうしたほうが良いとは言えません。 クラスの実装の際、そのクラスの使われ方を考慮しコーディングする必要があると思います。
技術系備忘録/C++/最適化小手先テクニック/ビットフィールドを活用すべし(メモリ節約編) のバックアップソース(No. All)
現: 2016-04-01 (金) 13:36:22
takatsuka
ぺージ情報
ぺージ名 :
技術系備忘録/C++/最適化小手先テクニック/ビットフィールドを活用すべし(メモリ節約編)
ページ別名 :
未設定
ページ作成 :
takatsuka
閲覧可
グループ :
すべての訪問者
ユーザー :
すべての訪問者
編集可
グループ :
なし
ユーザー :
なし
Counter: 2253, today: 2, yesterday: 3