何となく Blog by Jitta
Microsoft .NET 考

目次

Blog 利用状況
  • 投稿数 - 591
  • 記事 - 18
  • コメント - 2182
  • トラックバック - 183
ニュース
  • 検索エンジンで来られた方へ:
    お望みの情報は見つかりましたか? よろしければ、コメント欄にどのような情報を探していたのか、ご記入ください。
It's ME!
  • はなおか じった
  • 世界遺産の近くに住んでます。
  • Microsoft MVP for Visual Developer ASP/ASP.NET 10, 2004 - 9, 2009
サイト内検索
広告

記事カテゴリ

書庫

日記カテゴリ

ギャラリ

その他

わんくま同盟

同郷

 

間違いに、突っ込みがなかった。

フラグメンテーション あるはずなのにないより:

ガーベッジコレクタを持っている処理系なら、どれも返してもらえるけど、持っていない処理系では、1のみ。

ガーベッジコレクタの役割は、使われていないメモリを明らかにして、再利用可能にすることです。「明らかにすること」だけかもしれない。

引用元のところで、ガーベッジコレクタがすると言っているのは、正しくはデフラグメント処理で、これはガーベッジコレクタの役割ではありません。

でも、.NET Framewrok では、ガーベッジコレクションのタイミングでデフラグメントも実行されます。参照されているメモリがどこかに集められ、参照されていないメモリがまとめられます。

このことより、.NET Framework では、ヒープに取られたメモリ領域が固定している前提で作ってはいけません。というか、そんなこと、意識しなくてもいいわけだけど。しかし、アンマネージドな世界では、固定している前提で作られていたりします。アンマネージドな世界と行き来する場合は、デフラグメントの時に動かされないようにしなければならないことがあります。そこで、「こいつは動かさないでね」と、お願いすることもできます。あとは囚人さんのセッションを見てちょうだい。→THIS IS CLR


int*    ptr;

void huge()
{
    int*    hoge = (int) malloc(sizeof(int) * 100);
    ptr = &hoge[50];
}

void fuga()
{
    if (*ptr > *(ptr + 1)) {
        int b = *ptr;
        *ptr = *(ptr + 1);
        *(ptr + 1) = b;
    }
}

例示コードに意味を求めてはいけません。確保した領域を指す大域変数を作り、設定するところと使われるところが遠く離れている、という例です。hoge が動かないなら、ptr は hoge[50] のアドレスを指すことが保証されます。しかし、C 言語であっても、realloc によって動く可能性があります。hoge の場所が動けば、ptr は不正なアドレスを指すようになります。このような場合、ptr がどれくらい動いているかを計算しておき、realloc 後に hoge のアドレスが動いたら、ptr のアドレスも計算し直さなければなりません。

同じような間違いで、よく見かけるのが次のような例。


void main()
{
    char* fn = getFileName();   // [1]
    FILE* fp = fopen(fn, "r");  // [2]
    ...
    fclose(fp);
}

char* getFileName()
{
    char path[PATH_MAX];
    ... path にファイル名を入れる処理...
    return &path[0];
}

path はスタックに積まれるメモリです。getFileName() 関数のローカル変数なので、関数を抜けると他の何かによって上書きされます。しかし、処理系によっては、意図通りに動作しているように見えてしまいす。それは、使用されなくなったメモリ(この場合はスタック メモリ)は初期化されないからです。そのため、解放されて他者が使用可能になっても、そこに割り当てた内容はそのまま残っています。getFileName() 関数から抜けても、まだ初期化されずに残っているので、path として使えるように見えます。しかし、[1] と [2] の間に他の宣言を入れてみたり、他の関数を呼び出してみたりすると、あるいは意図通りに動作しなくなります。

処理系によっては、コンパイラが警告を出したり、エラーにしたりします。


8/27 関数名と、関数内の変数名がかぶっていたので修正。

投稿日時 : 2007年8月26日 22:13
コメント
  • # re: ガーベッジコレクタさん、ご苦労さま
    Blue
    Posted @ 2007/08/26 22:20
    最近似た質問がありました。
    http://www3.realint.com/cgi-bin/tarticles.cgi?pointc2+7841
  • # re: ガーベッジコレクタさん、ご苦労さま
    まきなす
    Posted @ 2007/08/27 10:26
    getFileName()の実装、いくらなんでもそれは・・・・
    え、よく見かける?

    テストをパスして正常に動作している
    ように見えるプログラムは多いですね。
  • # re: ガーベッジコレクタさん、ご苦労さま
    Jitta
    Posted @ 2007/08/27 22:58
    > 最近似た質問がありました。
    ひぃ~

    > javaだと当たり前にやっている事なので同じような事だと思っていたのですが。
    え~?

    > (Javaの場合は配列を返すのでコピーするという処理が走るのでしょう。
    > もしくは参照を返して、、、って微妙。。。)
    そっか。Java だとポインタがないから、か。
    ん~。。。C屋さんは、呼び出し元で確保しておいて、「ここに入れてね」を好むと思うけどなぁ?配列ごとコピーしていたら、時間がかかるじゃないですか。

    > 関数内のローカルなstatic変数を使ったことは、
    > これまであまりなかったように思います。
    これやると、「staticに持っているから、いつまでも有効だよね」と、呼び出し元が管理するエリアにコピーしない輩が出てくるんですよね。そうすると、つぶし合いをしちゃうわけで(-_-;


    > getFileName()の実装、いくらなんでもそれは・・・・
    ん。。。静的解析ツールが、「ローカル変数へのアドレスを返しています」と警告を出すプログラムを、何度か目にしています。もっともこれは static 宣言しているものを含むので、全部が全部間違いなわけではないのですが。。。

    > テストをパスして正常に動作している
    > ように見えるプログラムは多いですね。
    特集組もうか(笑)
タイトル  
名前  
Url
コメント