• ベストアンサー

移動可能メモリ

GlobalAlloc関数を調べていたんですが、GlobalLockしてメモリを固定するといっているのですが、その意味がピンときません。 GMEM_MOVEABLEで移動可能メモリの割り当てを行うようなんですが、 アドレスが移動するってどういうことなんでしょう? 固定メモリと移動可能メモリの違いってなんでしょうか?

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

  • ベストアンサー
  • onosuke
  • ベストアンサー率67% (310/456)
回答No.1

まず、GlobalAlloc()やLocalAlloc()がWindowsの歴史的な経緯から残っている遺物で、今の時代にはそぐわないものだということを知っておいてください。 # Windows3.X時代、16bit CPUにあわせたメモリ管理の仕組み # に対応したものです。 >アドレスが移動するってどういうことなんでしょう?  「OSによって、データ格納先アドレスが勝手に変更される可能性がある」 ということです。(メモリデフラグ処理が原因) GMEM_FIXEDやGlobalLock()は、  「今から、データ格納先のアドレスポインタをプログラム内で保持します。だから、勝手にデータ格納先アドレスを変更しないでください」 というプログラムからOSへの宣言です。 # プログラムは、「アドレス10番地にデータが格納されている」 # と思っているのに、OSが勝手にアドレス10番地からアドレス20番地へ # データを移動させちゃったら困りますよね? >固定メモリと移動可能メモリの違いってなんでしょうか? プログラムからOSへの宣言の違いです。  ・固定メモリ…絶対、OSで勝手にデータ格納先アドレスを変更するな!!!  ・移動可能メモリ…プログラムで使っていない間は、OSが自由にデータ格納先アドレスを変更しても良いよ。  但し、上記の話「メモリデフラグ処理でデータ格納先のアドレスが勝手に変更される」が該当するのは、昔のWindowsだけです。  後継のWindowsNT,2000,XPでは、メモリデフラグを行っても、プログラムから見たデータ格納先アドレス(仮想アドレス)は変化しません。実際のデータ格納先アドレス(物理アドレス)が変化するだけです。  つまり、現在のCPUでは「GlobalLockしてメモリを固定するといっている」こと自体、必要ない処理、無駄な処理になります。  HeapAlloc()を利用しましょう。

dotneer
質問者

お礼

GlobalAlloc関数が昔から使われていたWindowsでの仕様を考えたもの だったんですね。  移動可能メモリというのはメモリデフラグ処理というのが絡んでいたんですね。 とてもよく分かりました。 ありがとうございます。

関連するQ&A

  • クリップボードへのコピー

    あるHPのコードを参考に文字をクリップボードへ コピーするコードを書いてみましたが、エラーが できます。なにかおかしいかご指摘いただけないでしょうか? HGLOBAL hText; wchar_t *pText; hText = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 4); pText = (wchar_t*)GlobalLock(hText); lstrcpy(pText, L"abc"); GlobalUnlock(hText); OpenClipboard(NULL); EmptyClipboard(); SetClipboardData(CF_TEXT, hText);//ここでヒープが壊れていると起こられます。 CloseClipboard(); もっとも単純なテストコードです。 いろいろとチェックを手抜きしてますが、とりあえずOKとします。

  • GlobalAlloc について

    GlobalAlloc について 質問させて下さい。 VC++ 2005 MFC で開発しております。 仕様の概要と致しまして、 ::GlobalAlloc()でHGLOBALを取得し、 メンバ変数に格納(Arrayでリサイクルしていくイメージ)した後、スレッドを走らせ格納したHGLOBALを 使い処理をした後に、GlobalFree()でメモリを開放します。 アプリの仕様上、スレッドの処理に少々時間がかかり GlobalAlloc()とGlobalFree()が必ずしも一対一で実行されず、 スレッドのGlobalFree()が実行される前に別のGlobalAlloc()がくることがあります。 このような場合、下記のように確保するヒープ領域の取得したアドレスが 少しずつ増えてしまい、最終的には取得できなく(GlobalLockでNULLポインタ)なってしまいます。(4GB越え) 8バイトずつアドレスが増えていくとして ------------------------------------------------- ・一対一の場合 (同じアドレスが使用できる) 確保 開放 (1)0008 (2)0008 (3)0008 (4)0008 (5)0008 ・一対一でない場合 (開放される前に確保するので新しいアドレスを使用してしまう) 確保 開放 (1)0008 (2)0008 (3)0008 (4)0016 (5)0008((3)メモリ) (6)0024 (7)0032 (8)0040 (9)0016((4)メモリ) (10)0024((6)メモリ) (11)0032((7)メモリ) (12)0048 : : : ------------------------------------------------- GlobalFree()がもれているのではなく メモリを確保したものは遅れはするものの必ず開放はしています。 このような場合、上記の「一対一でない場合」の (6)で「0024」番地ではなく「0008」番地からメモリを確保することは出来ないのでしょうか? 確保と開放が一対一に統合されていればこのような問題はない(常に同じアドレスを使用できるため)のですが、 アプリの使用上、仕方ないと考えております。 説明が複雑になってしまい、わかりにくいとは思いますが、 お詳しい方がおられましたら、ご教授の程宜しくお願い致します。

  • Win32APIでのメモリ管理について

    C→malloc関数 C++→new演算子 Win32API→GlobalAlloc関数 とWin32APIでのメモリ管理の方法にはいろいろありますが、どれを使うのが一番実用的なのか、どれが一番効率的なのかが知りたいです。 あとWin32APIにはHeapAllocという関数もあるようですが、上記の3つは使わずにこの関数を使用したほうがよいのでしょうか。

  • htmlソースを一文字ずつ取得するには・・

    私は猫でもわかるネットワークプログラミングをよんでふと思ったのですが・ HTMLソースを空白行も含め縦に並べたいのです たとえば・・ < h t m l > ってな感じで・・ つまりは printf("%s(%cでも・・)",一文字); ってな感じにしたいのです・・ 一応作りかけのソース張っておきます。。。。 wininet使ってます・・ //省略 //インターネット(wininet)開始 hInet = InternetOpen("ユーザー名収集プロトタイプ",INTERNET_OPEN_TYPE_PRECONFIG, NULL,NULL,0); hUrl = InternetOpenUrl(hInet,szUrl,NULL,0,0,0); //lpszSrcに1バイトのみ確保 hMem = GlobalAlloc(GHND,1); lpszSrc = (char *)GlobalLock(hMem); //読み出すものがなくなるまで読み出す while(1){ InternetReadFile( hUrl,szBuf,(DWORD)sizeof(szBuf) - 1,&dwRead); szBuf[dwRead] = '\0'; //読み出すものが無くなったらループを脱出 if (dwRead == 0){ break; } //必要バイト数の計算 dwTotal += dwRead; //確保領域の大きさ変更 hMem = GlobalReAlloc(hMem,dwTotal,GMEM_MOVEABLE); if(hMem == NULL){ perror("再アロケート失敗\n"); } lpszSrc = (char *)GlobalLock(hMem); if(lpszSrc == NULL){ perror("メモリ領域確保に失敗\n"); break; } strcat(lpszSrc,szBuf); printf("%s\n",szBuf); } //メモリの開放 GlobalUnlock(hMem); GlobalFree(hMem); //インターネットハンドルの開放 InternetCloseHandle(hUrl); InternetCloseHandle(hInet); return 0; }

  • GDIによるメモリ上からの画像データ読み込みに関して

    開発環境はVC++/CLIです。 アンマネージ型のCOMオブジェクトの扱いで困っております。 JPEGやPNGなどの画像データを保存したunsigned char型配列から、Gdiplus::Bitmap型を作ろうとしています。 unsigned int imagesize; // 画像のバイト数が格納されている array<unsigned char>^ image = gcnew array<unsigned char>(imagesize); //画像のデータが格納されている 事前にこのようなデータを用意し、以下のように記述しました。 HGLOBAL hResourceBuffer = GlobalAlloc(GMEM_MOVEABLE , imagesize); void* pResourceBuffer = GlobalLock(hResourceBuffer); CopyMemory(pResourceBuffer, &image, imagesize); IStream* pIStream = NULL; CreateStreamOnHGlobal(hResourceBuffer, TRUE, &pIStream) data->bmp = new Gdiplus::Bitmap(pIStream); pIStream->Release(); GlobalUnlock(hResourceBuffer); GlobalFree(hResourceBuffer); しかしながら、上記のコードだと、CopyMemory時に「保護されたメモリに書き込もうとした」といったエラーが発生します。 Webで色々検索しましたが、全て似たような記述で動作していました。 何が問題なのでしょうか? 尚、上記と同様の画像データ配列を使って、System::Drawing::Bitmap型に格納したとき、画像が正常に表示されることを確認しております。 画像のバイト数に於いても取得したデータに間違いはなく、やはりメモリ関連の問題だと思うのですが…。 MemoryStream^ memst = gcnew MemoryStream(image); Bitmap^ bmp = gcnew Bitmap(memst); memst->Close(); Graphics^ im = pictureBox1->CreateGraphics(); im->DrawImage(bmp, 0, 0, 100, 100); delete bmp;

  • 外部メモリの割り当て

    外部メモリの割り当てについて教えてください。 V850のアドレス空間に外部メモリはどこにどう割り当てられるのでしょうか。よろしくお願いします。

  • メモリ違反でソフトが強制終了してしまいます。

    コンパイルして実行すると ttp://kei100.jp/diary/images/20050612_0.png このようなメッセージが表示されてしまいます。 #include <windows.h> #include <stdio.h> #include <string.h> void main(void) { HANDLE hFile; HGLOBAL hg = GlobalAlloc(GMEM_FIXED, 1000); char* test = "test"; LPTSTR aaa="spacetestspace"; char* bbb = NULL; char ccc[5]; aaa=(char*)GlobalLock(hg); bbb = strstr(aaa, test); strncpy(ccc, bbb, strlen(test)); printf("ccc = %s \n", ccc); GlobalUnlock(hg); GlobalFree(hg); GlobalFree(aaa); } どなたか解決方法を知っている方、回答よろしくお願いします。

  • c++ メモリの確保を動的に変更する

    VC++2008 Express版で以下のプログラム(第1引数をクリップボードにセット)を作成しましたがメモリの確保量を自動的に調節するようにしたいのですが、どうしたらよろしいですか #include <stdio.h> #include <windows.h> void main(int argc,char *argv[]) { OpenClipboard(NULL); int iStrLen = 8;//★ここを調整したい★ HGLOBAL hMem = ::GlobalAlloc(GMEM_FIXED, iStrLen); LPTSTR pMem = (LPTSTR)hMem; ::lstrcpy(pMem, (LPCTSTR)argv[1]); ::EmptyClipboard(); ::SetClipboardData(CF_TEXT, hMem); ::CloseClipboard(); }

  • ReadEventLogについて

    教えてください。 ReadEventLogでイベントログ情報を取得したいのですが、わからない所があります。 ReadEventLogのpBufはEVENTLOGRECORD型なのです。ですが、メモリを確保するためGlobalAllocを使いたいのですが、HGLOBAL(Void)型なのでキャストしてもうまくいきません。 型を変える方法があるのでしょうか? あるのであれば教えてください。 [ソース一部] EVENTLOGRECORD *pBuf = NULL; HGLOBAL hDIB; hDIB = GlobalAlloc(GMEM_FIXED, BufSize); pBuf = (EVENTLOGRECORD)hDIB; //★ここでエラー bResult = ::ReadEventLog(hEventLog,EVENTLOG_FORWARDS_READ | EVENTLOG_SEQUENTIAL_READ,0,pBuf,BufSize,&ReadBytes,&NextSize);

  • gccで割当可能メモリ領域を取得する方法

    MS-Cでは、割当可能メモリ領域を取得するのに、 「_freect」という関数を使用できますが、 GCCでは、これに該当する関数というのは 存在するのでしょうか? ご存知な方がおられましたら、教えていただけますでしょうか?