メモリマップドファイルを使用した可変長メモリプールの実装方法

このQ&Aのポイント
  • メモリマップドファイルを使用して可変長メモリプールを実現する方法について説明します。
  • メモリマップドファイルを読み取り専用で開くことで、大きなファイルを一度にメモリに読み込む必要がなくなります。
  • メモリマップドファイルを操作する際は、ポインタ操作やオフセットを利用してアドレスを管理します。これにより、必要なデータのみをメモリ上に確保し、高速な処理を実現することができます。
回答を見る
  • ベストアンサー

メモリマップドファイルを可変長メモリプールとして

だいぶ製作中のアプリケーションも、自作ファイル形式も かなり大きい(よほどの場合により数百MBとか)ファイルを扱う可能性が生じてきたので 必ず全部メモリに読み込むのは推奨できない、という状況になりました。 そこで 既存のファイルからは読み取り専用で メモリマップドファイルとして開き、普通のメモリ上に読み込まずともポインタ操作できるようにし 操作したい場合は読み書きできるメモリマップドファイルを、自分のアプリの指定フォルダに作業領域として作ったところから使用中だと判断出来るようにしておいて確保し アドレスはオフセット等で管理し、ポインタを移し替えたりする、という手を使い また、うまく処理を切り分けてやることにより 重要な個所についてはメモリ上に確保し、そこにデータにフィルタ演算するついでに移し替えたりするなど さまざまな手によって かなりの速度も実現出来ることが確認できました。 これはつまり、メモリではなくメモリマップドファイルを 可変長メモリプールとして使うという形になっています。 ただ、昨日思いつきで作って、とりあえず十分快適に動作は出来るけども、最適解かどうかは手探り状態、ともいえるので よりよい方法が考えらるならぜひ知っておきたいです。 と…書いてる途中で 今は「使用中」「未使用」のフラグとそのサイズを持たせたリストを、一方向にnextポインタでつなぐのみ、となっていますが 空きリストのみ(も?)収集して…という方法の概念を思い出しました。 あまり複雑になるとバグが出る危険性はありますが、試す価値はありそうです。 ただ ・まず、メモリマップドファイル自体については、作った後はそのファイル自体は固定サイズ、ってことで良いでしょうか? ・可変長メモリプールなどのアルゴリズムについて、把握するのに何日もかかりそうなあまり巨大なコードになりすぎない範囲で、考察したりオープンソースで作ったりしているサイトなどがあれば教えていただきたいです。

質問者が選んだベストアンサー

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

メモリマップドファイルは標準には含まれない (はず) なので, その実装などは使っているシステムに依存すると思います. 例えば, Windows なのか FreeBSD なのか Linux なのかによって違うかもしれませんよ.

LongSecret
質問者

お礼

ご回答ありがとうございます♪ それは重要な情報ですね。 考えてみれば、OSと密接に関係してそうですからね。 将来的な移植の可能性を考えると、あまり長すぎるコードを組むのも得策ではないかもしれません。 とりあえずは、WindowsのXP以降を対象と考えたいところです。 ちょっと確認してみたら、現在は宣言と定義で占めて550行程度でした。 アプリケーションの総合的なパフォーマンスを考えると これはかなり重要な部分ではあるので 逆に、内容にもよりますが、1000行くらいまでなら移植するのもそれほどきつくはないかな、と思っています。

LongSecret
質問者

補足

(12/27) 久しぶりに見てみたら メモリマップドファイルではなくメモリ上での可変長プールで、単独での解放手順がないバージョンはEfficient C++に載っていました。 やはり単独での解放手順があるのとないのとでは結構必要事項の量が変わってきますが (その他の色々なサイトなども含め)少なくとも、現状かなりいい線いってることは確かなはずと感じたことと システム依存という情報が得られたこと(この情報があるだけでかなり色々なことが考えられますので)を踏まえ 今回の質問は締め切りとさせていただきます。 ども、ありがとうございました。

関連するQ&A

  • MySQL5.5 MEMORYテーブル可変長

    MySQLのMEMORYエンジンを使用したテーブルについて質問です。 varcharは可変長の認識だったのですが、MEMORYエンジンの場合、固定長として扱うのか・・・ InnoDBの時は2GB程のレコードだったのがMEMORYに変更したところmax_heap_table_size=7GBを超えてしまいました。 質問の内容は以下です (1).varcharはMEMORYテーブルでは値の長さに関わらず領域を確保するのでしょうか (2).MEMORYテーブルで可変長を扱う方法はあるのでしょうか MySQLのバージョンは5.5.28です。 難解な文章で申し訳ないですが、ご存知の方いらっしゃいましたらご教授のほどよろしくお願いいたします。

    • ベストアンサー
    • MySQL
  • 可変長文字列で困ってます

    宿題出で全くわかりません。 ここを実装っていうところがわかりません。 よろしくお願いします。 /* 単方向リストプログラム */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <assert.h> #include <crtdbg.h> /********************* リスト処理部 *********************/ /* リストセル 構造体定義 */ typedef struct cell { char *string; struct cell *next; } CELL, *PCELL; /* PCELL ListInsert(PCELL pos, const char *string) 指定されたセルの次に,新しいセルの挿入する PCELL pos : 挿入位置のセルを指すポインタ char *string : 新セルに含める文字列 戻り値: 新しく確保したセルのアドレス メモリ確保に失敗した場合にはNULL */ PCELL ListInsert(PCELL pos, const char *string) { PCELL pNewCell; pNewCell = calloc(1, sizeof(CELL)); if (pNewCell != NULL) { // ここを実装する } return pNewCell; } /* void ListDelete(PCELL pos) セルの削除.pos の指すセルの次のセルを削除する. PCELL pos : 削除するセルの直前のセルを指すポインタ */ void ListDelete(PCELL pos) { // ここを実装 } /* void ListDestory(PCELL header) リスト全体の削除 PCELL header : ヘッダセルへのポインタ */ void ListDestroy(PCELL header) { // ここを実装 }

  • COBOLでの可変長定義について

    unix環境下でCOBOL85を使用しています。 あるデータを可変長でWRITEしていくのですが、 データにヘッダー情報みたいなものが付加されてしまい困っています。 ヘッダー情報を付加しないようにするにはどうすればいいのでしょうか? 定義:  FD Aファイル RECORD IS VARYING 1 TO 100 DEPENDING ON A-CNT.  01 A-DATA PIC X(100). とか  FD Aファイル RECORD IS VARYING IN SIZE DEPENDING ON A-CNT.  01 A-DATA PIC X(100). というパターンで試しています。 Aファイルにaaaという3バイトデータをWRITEすると、 COBOL85020315020304・・・・・aaaというデータが出力されます。 あるコボラーに聞くと「定義がおかしいからでしょう」と言ってたのですが、 どうおかしいかは本人もわからないようです。 どうすればヘッダー情報(COBOL85020315020304・・・・・)がつかず、 可変長でWRITEできるのでしょうか?教えて下さい。

  • 引数の可変

    覚えたての引数の可変を使ってみた素人であります。(独学です 見よう見真似で書いた為、目茶苦茶だと思われます。 自分で簡単なexeファイルを作ってみていて 引数の可変が必要となったので付け足そうとしていたのですが、「引数の可変」部の他 意外にもfor文からもエラーが出ました(while使えば済む話なのですが) 今までfor文をあまり使わずwhile文ばかり使っていた為、for文の基本的な構文が失敗しているのかもしれません。折角だから使ってみようとした結果がこれです。 #include <stdio.h> #include <locale.h> #include "DxLib.h" #include <string.h> #include <stdarg.h> int i; ・・・略・・・ class CharsOut{ ____int ypixel; ____char *hangar; ____int size; ____int HowMany; ____int list; public:   ____int CharsOuting(int HowMany,int ypixel,int size,...); }; int CharsOuting(int HowMany,int ypixel,int size,...){ ____va_start(list,HowMany); ____for (i=0;i<HowMany;i++){ ________printf("%s",va_arg(list,char *)); ____} ____va_end(list); ____return 0; } ypixel、size...といった変数等は気にしないでください。 成功していたらコードを足すつもりでした。 自分がやりたいことは、main関数から変数HowMany,*hangar等を受け取り 文字列*hangarを引数の分出力したいのであります。引数の可変は*hangarを何個か渡すつもりだったので使用しました。 こんな感じに使うつもりでしたc.CharsOuting(2,0,32,"I am ", "hangury"); ※リストは(int HowMany,int ypixel,int size,...)です ※ハングリーのスペルが違う等ということはとてつもなくどうでもいいことなのです。 自分で「main関数から*hangarを受け取り」と書いておきながらリストに*hangarがない時点でおかしいと思ってはいるのですが、記述の方法が分からないので書けません。 以下エラー (名前とか一部改変・不要な部分省略 1>------ ビルド開始: プロジェクト:(≡ω≡.), 構成: Debug Win32 ------ 1>コンパイルしています... 1>soucer.cpp 1>error C2040: 'i' : 'int' は 'int [5]' と間接操作のレベルが異なります。 1>error C2065: 'list' : 定義されていない識別子です。 1>error C2440: '=' : 'int' から 'int [5]' に変換できません。 1>配列型への変換はありませんが、参照またはポインタから配列への変換があります。 1>error C2446: '<' : 'int' 型から 'int *' 型への変換ができません。 1>整数型からポインタ型への変換には reinterpret_cast、C スタイル キャストまたは関数スタイル キャストが必要です。 1>error C2040: '<' : 'int [5]' は 'int' と間接操作のレベルが異なります。 1>error C2105: '++' には左辺値が必要です。 1>error C2065: 'list' : 定義されていない識別子です。 1>error C2065: 'list' : 定義されていない識別子です。 1>ビルドログは "file://c:\・・・\Debug\BuildLog.htm" に保存されました。 1>(≡ω≡.) - エラー 8、警告 0 ========== ビルド: 0 正常終了、1 失敗、0 更新不要、0 スキップ ========== 文章能力なくて申し訳ありません。 ご回答頂ければ幸いであります。宜しくお願いします。 OS:WinXP コンパイラ:Visual C++

  • C言語のメモリ領域確保

    ポインタ変数ををmain関数で宣言し、関数test()にて必要分だけ領域確保してそのアドレスをmain関数のポインタ変数に渡して利用することは可能でしょうか。 (サイズのわからないテキストデータを、十分に大きな配列に入れるのではなく、関数でメモリを動的確保して無駄の無い配列に入れたい等) C言語ではやはり無理で、構造体のリストにするのが一番でしょうか。 初歩的なことで申し訳ありませんがどなたかお願いいたします。

  • 動的なメモリ領域の確保

    double型変数5個分のメモリをmalloc関数により確保し,その確保した要素のアドレスを表示するように,プログラムを作る問題で、 (注)に「 %pで表示するためには,double型へのポインタ(double *)をvoid型へのポインタ(void *)にキャストする必要がある.」と書かれていたのですが、どういうことでしょうか? 以下のようでいいのでしょうか? #include<stdio.h> #include<stdlib.h> #define COUNT 5           // 動的に確保するメモリ領域数を示すマクロ定数の定義 int main(void) {  // 動的に確保するメモリ領域のアドレスを保持するポインタ変数の宣言  double * pointer;  int i;                  // for文で使用する変数の宣言  // int型変数5個分のメモリ領域を確保  pointer = (double *)malloc(sizeof(double) * COUNT);  if(pointer == NULL) {        // メモリ領域の確保が失敗した場合   printf("メモリ領域を確保できませんでした.\n");   exit(1);                // プログラムの終了  }  for(i = 0; i < COUNT; i++)   printf("%d番目のアドレスは%pです.\n", i + 1, pointer + i);  free(pointer);            // 確保したメモリ領域の解放  return 0; }

  • reallocでメモリを再確保するには?

    こんにちわ, 今, 「すでに動的確保しているメモリをその型分1サイズだけ増やす」というプログラムを考えています。 具体的には, char* str_p; a=calloc(str_p, sizeof(char)); /*ここから問題のプログラム(実際はずっと動くので無理です*/ while(1) { a=realloc(str_p, sizeof(str_p)+sizeof(char)); } ・・・・・・ これだと,私的にはsizeof(str_p)で今のサイズを調べ,それにsizeof(char)を加えることで次々に1サイズ大きいメモリを再確保できると思ったのですが,ポインタのサイズを指していてそれにchar型のサイズをたしていていつも固定サイズになるみたいでうまくいきません。 どうすれば,char*などポインタ型の変数の大きさを調べられるのでしょうか。 また,どうすれば,1サイズずつ大きくできるのでしょうか。 よろしくおねがいします。

  • メモリ領域確保に関して

    C言語を始めて3ヶ月の初心者です。 下記のような定義で、領域確保をしたいのですが、 うまい方法がわかりません。 ご存知の方いらっしゃいましたら、 御知恵をお貸し下さいませんでしょうか? <test.h> ================================== #define SIZE_A (5) /* 親構造体 */ typedef struct { int testInt; testSmallStructT *testSmall; // 7バイト構造体の配列 char *testChar; // SIZE_A分の領域*配列数 } testBigStructT; /* 7バイト構造体 */ typedef struct { char str1[3]; char str2[4]; } testSmallStructT; /* メンバ変数 */ testBigStructT gTest[10]; ================================== ここで、あらかじめ全体の領域サイズを算出して、 mallocにてエリア確保を行う方法を求めてます。 また、多数にmallocを使用するとメモリ確保失敗時に、 それまで確保したエリアの開放を行わなくてはいけなくなる懸念から、 できるだけ使用しないようにしたいのです。 メンバ変数gTestを10の配列で持ち、構造体testBigStructTの、 要素testSmallとtestCharを可変の配列として扱いたくポインタ定義をしており、 更に、testCharにSIZE_A(5byte)の領域を確保しようとしております。 最終的には、下記のような使い方をしたいのですが、 メモリ確保の方法がわかりません。 =================================== (EX:) strcpy(gTest[0].testSmall[0].str1,"aaa"); strcpy(gTest[3].testSmall[2].str2,"bbb"); strcpy(gTest[6].testChar[3],"cccc"); =================================== 開放は下記の記述で問題ないと思っております。 free(gTest); 大変申し訳御座いませんが、 ご指摘・ご指導願いませんでしょうか? どうか宜しくお願い致します。

  • 仮想メモリの数値について(初期サイズ・最大サイズ)

    windowsXPを使っている者です。 仮想メモリの設定について伺います。 あるサイトに 「使用するアプリケーションに応じ、仮想メモリ領域は初期サイズと最大サイズの間で可変します。そのため断片化が起こりやすくなります。この二つのサイズを同一サイズとしておくと、仮想メモリ領域の断片化は起こりにくくなります。」 と書いてありました。 デフォルトでは初期サイズ2046、 最大ファイル4092となっているのですが、変更した方が良いのでしょうか?またそうだとしたらどのぐらいのサイズにすれば良いのでしょうか。 しかし、なぜデフォルトでは同じ数値になってないのだろうか・・

  • メモリマップドファイルは動作原理的に…

    QueryPerformanceCounterを使ってそれほど複雑でない関数でのベンチマークを行ったところ 今のところ全ての場合においてメモリマップドファイルのほうが単純なファイルの読み書きより高速でした。 (こんないい機能があったなんて…(笑)) それほど差がない場合もありましたが、場合によっては100倍以上もの差になった時もあります。(実メモリと比較したら全然ではありますが) メモリに困ることは最近それほどなかったので、、仮想メモリのスワップアウトが起きるとどれくらいの速度で動作することになるのか 全く実感できなかったのですが 1.このメモリマップドファイルは 原理的に、それを明示的に行うようなものとみなして問題ないでしょうか? 2.書き込み可能な属性で作り CreateFileMappingに指定するサイズがファイルサイズより大きかった場合はファイルが拡張され、それ以下だった場合はそのままのようです。 しかし、実際にそれ未満の数値を指定して、その指定したサイズ以上のアドレスのところへ書き込もうとすると、メモリの場合サクッと不正終了してくれるので逆におかしいところがあることが分かるので安心できるともいえるのですが、こちらはファイルサイズに余裕があれば、指定したサイズを超えた部分へもどうやら書き換えることができてしまうようです。 この場合、もしファイルサイズすら超えた数値へ間違って書き込み命令を出してしまった場合、切り捨てられるのでしょうか?それともどこか別のところが書き換えられてしまう危険があるのでしょうか? 3.また、試したら出来てしまったのですが 別のポインタを使って操作するのは「通常の動作」でしょうか? それとも未定義の動作でしょうか? 例) ・ ・ ・ char *a = (char*)MapViewOfFile( hMap, FILE_MAP_WRITE , 0, 0, 0); wsprintf(a,"aaaaaa"); char *b= a+3; wsprintf(b,"bbbbbb"); b+=3; wsprintf(b,"ccc"); UnmapViewOfFile( a ); ・ ・ ・ 結果: aaabbbccc