ショッピングモール  コエンザイムQ10(CoQ10) クレンジング  コエンザイムQ10(CoQ10) 化粧水


【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※マルチポスト(多重投稿)は謹んで!

 詳しくはこちら



 本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール   掲示板1こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧

No.3417

メモリの一括解放関数
投稿者---kolona(2005/02/10 22:23:35)


環境は
winXp とwinMe
borland c++ compiler 5.5.1
です

今、メモリの一括解放関数をつくっています。
garbageという構造体に、
記憶されているデータの種類(解放の方法が違う)、データへのポインタ、データサイズ、管理ID、garbage構造体へのポインタ
という5項目を記録し、Gc関数が呼び出されるたびにリンクリストを追加するという仕組
みを考えています。(JAVAとかのガーベジコレクションを少し意識しています。)
以下に各関数の簡単な仕様を示します。

int Gc(char *namp,void *p,int size);
リストに追加していく関数。*nampに'f'か'm'を指定することでファイル構造体か、malloc等による動的に確保されたメモリ領域かを指定する。
*pにはデータへのポインタを指定する。sizeにはデータのサイズを指定する(データサイズは現在の関数では必要ではないが、将来の拡張で必要かもしれないので)。
各構造体には一意的なIDを割り当てて管理する。登録時に先頭からリストをたどるとき、抜けた番号があれば、そのIDを使って登録する。理論上は2147483647-3個のデータを格納できる計算。登録が終わったら登録IDを返す。
int allfree(void);
記録されているデータとメモリを全て解放する
int linkdel(int ID);
リンクリストからIDに合致するデータを消去し、記録されていたメモリ領域も開放する。
void printst(void);
リンクリストに記録されたデータを表示する(デバッグ用)

このような仕様で関数を作成し、一応動作確認をしましたが、試行錯誤しながらつくったので、仕様や書き方に自分で気づかない間違いがあるかも知れません。
特にvoidを使ったポインタの記憶は邪道かもしれず、自信がありません。
以下のソースではバグは出ていませんが、メモリを管理する関数なのでバグが内在している可能性がとても高いと考えています。
ここはこう書いた方が良いとか、この仕様は良くないとか指摘頂ければと考え、投稿しました。以下にソースを示します。

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define MAXN 255

//使用されているメモリ領域の種類とポインタ,サイズ,IDを記録する
typedef struct garbage{
 int syu;
 void *memoryp;
 int size;//何かに使うかも
 int ID;
 struct garbage *next;
}Garbage;

Garbage garbagecollection_head;//Garbage構造体リストの先頭

int allfree(void);
int Gc(char *namp,void *p,int size);
int linkdel(int ID);
void printst(void);

int main(void){

FILE *f1,*f2,*f3;
int y,id;
char fm1[MAXN]="read.txt1",fm2[MAXN]="read.txt2";
char *sp1,*sp2,*sp3;

garbagecollection_head.next=NULL;

sp1=malloc(10000000);
Gc("m",sp1,sizeof(*sp1));

sp2=malloc(10000000);
id=Gc("m",sp2,sizeof(*sp2));

sp3=malloc(10000000);
Gc("m",sp3,sizeof(*sp3));
//printst();
linkdel(id);
//printst();

f1=fopen(fm1,"wb");
Gc("f",f1,sizeof(*f1));
f2=fopen(fm2,"wb");
Gc("f",f2,sizeof(*f2));
f3=fopen("read.txt3","wb");
Gc("f",f3,sizeof(*f3));
//printst();

fprintf(f1,"read.txt%d%c%c",1,13,10);
fprintf(f2,"read.txt%d%c%c",2,13,10);
fprintf(f3,"read.txt%d%c%c",3,13,10);

printf("終了\n");
gets(fm1);
allfree();
gets(fm1);
return 0;
}
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/* 
garbage collectionの真似する関数。
fopen,malloc,calloc, によって確保されたメモリ領域を記憶し,
allfree 関数でまとめて解放する
*namp は f ファイルポインタ登録, m maloc又はcallocポインタ登録
 f又はm(領域登録) の場合はsizeに領域のサイズ(Byte)を指定
  返り値は登録されたIDナンバー。任意のタイミングで開放する時はこのIDを使う
種類は 1 fopen 2 m(c)alloc
*/
int Gc(char *namp,void *p,int size){

int x;
Garbage *gc,*gcp;

x=1;
gc=&garbagecollection_head;
gcp=malloc(sizeof(Garbage));
if(gcp==NULL){allfree();exit(0);}
while(1){//リストの最後もしくは抜け番号を探索
  if(gc->next==NULL){//リストの最後に到達
    gc->next=gcp;
    gcp->next=NULL;
    x++;break;
  }
  else if((x+1!=gc->next->ID)){//抜け番発見
    gcp->next=gc->next;
    gc->next=gcp;
    x++;break;
  }
  gc=gc->next;
  x++;
}
if(*namp=='f'){
  (FILE*)(gcp->memoryp)=(FILE*)p;
  gcp->syu=1;
}
else{
  gcp->memoryp=p;
  gcp->syu=2;
}
gcp->size=size;
gcp->ID=x;
return x;
}
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/* 
Gcで確保されたメモリ領域をすべて開放する
*/
int allfree(){

Garbage *p,*buf;

p=&garbagecollection_head;
printf("All Free\n");
if(p->next==NULL)return 1;
p=(p->next);
do{
  if(p->syu==1){printf("ID %d  ファイルポインタ開放\n",p->ID);
    fclose((FILE*)(p->memoryp));
  }
  else{printf("ID %d  メモリ領域開放\n",p->ID);
    free(p->memoryp);
  }
  buf=p;
  p=p->next;
  free(buf);
}while(p!=NULL);
return 1;
}
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/* 
IDナンバーに該当するメモリ領域を開放する
*/
int linkdel(int ID){

Garbage *p,*buf;

p=&garbagecollection_head;
if(p->next==NULL){return 1;}
while((p->next)!=NULL){
  if(p->next->ID==ID){//次にくる構造体IDが一致した
    buf=p->next;
    p->next=p->next->next;//リストから当該IDを持つ構造体を削除
    if(p->syu==1){p=buf;
      fclose((FILE*)(p->memoryp));
    }
    else{p=buf;
      free(p->memoryp);
    }
    //構造体自身を解放
    free(p);
    break;
  }
  p=(p->next);
}
return 1;
}
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*
構造体に格納されているデータを表示する関数
*/
void printst(void){
Garbage *p;
int x;

printf("**************************************************************\n");
p=&garbagecollection_head;
while(p->next!=NULL){
  p=p->next;
  if(p->syu==1){printf("FILE \n");}
  else {printf("malloc\n");}
  printf("ID=%d\n",p->ID);
  printf("size=%d\n\n",p->size);
}
printf("**************************************************************\n");
}




この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:メモリの一括解放関数 3418 あかま 2005/02/10 22:54:30
<子記事> Re:メモリの一括解放関数 3419 あかま 2005/02/11 00:21:34


No.3418

Re:メモリの一括解放関数
投稿者---あかま(2005/02/10 22:54:30)


とりあえずこれ。

Gc("m",sp1,sizeof(*sp1));

sizeof(*sp1)のサイズがどうなってるか出力してみるとよい。


この投稿にコメントする

削除パスワード

No.3419

Re:メモリの一括解放関数
投稿者---あかま(2005/02/11 00:21:34)


>ここはこう書いた方が良いとか、この仕様は良くないとか指摘頂ければと考え、投稿しました。以下にソースを示します。
ちょっと面白そうだったので私も書いてみました。
mallocしてからGcに登録するのはめんどくさいのでGcmallocなんて関数を作ってmallocと同時にGc登録が出来るようにしてみました。
アドレスは重複しないのでIDを削除して代わりに使っています。

もしガーベジコレクションを作ってみたいなら
http://i.loveruby.net/ja/rhg/gc.html
この辺を読むと幸せになれるかも。


#include <string.h>
#include <stdlib.h>
#include <stdio.h>

//使用されているメモリ領域の種類とポインタ,サイズ,IDを記録する
typedef struct garbage{
 int syu;
 void *memoryp;
 int size;//何かに使うかも
 struct garbage *next;
}Garbage;

Garbage *garbagecollection_head;//Garbage構造体リストの先頭

int allfree(void);//GcmallocとGcfopenで管理されているメモリを全て解放する
void *Gcmalloc(int size);//sizeの大きさのメモリを確保して返す
FILE *Gcfopen(char *filename,char *mode);//ファイルオープンしてファイルポインタを返す
void setGclist(Garbage *);//リストに追加するためのGcmallocとGcfopenのサブ関数

int Gcfree(void *ptr);//ptrに渡したGcmallocやGcfopenで確保したメモリを解放する
void printst(void);//Gcで管理されている情報の出力

int main(void){

    FILE *f1,*f2,*f3;
    int y,id;
    char *sp1,*sp2,*sp3;
    
    printf("6つ確保\n");
    sp1=Gcmalloc(5000);
    sp2=Gcmalloc(7000);
    sp3=Gcmalloc(8000);

    f1=Gcfopen("read.txt3","wb");
    f2=Gcfopen("read.txt3","wb");
    f3=Gcfopen("read.txt3","wb");
    printst();
    
    printf("\n2つ解放\n");
    Gcfree(sp1);
    Gcfree(f2);
    printst();
    
    printf("\n残り全部解放\n");
    allfree();
    printst();
    
    return 0;
}

void *Gcmalloc(int size){
    Garbage *gp;
    gp = malloc(sizeof(Garbage));
    gp->memoryp = malloc(size);
    gp->syu = 'm';
    gp->size = size;
    setGclist(gp);
    return gp->memoryp;
}

FILE *Gcfopen(char *filename,char *mode){
    Garbage *gp;
    gp = malloc(sizeof(Garbage));
    gp->memoryp = fopen(filename,mode);
    gp->syu = 'f';
    gp->size = sizeof(FILE);
    setGclist(gp);
    return gp->memoryp;
}

void setGclist(Garbage *gp){
    gp->next = garbagecollection_head;
    garbagecollection_head = gp;
}
/* 
Gcで確保されたメモリ領域をすべて開放する
*/
int allfree(){
    Garbage *p,*buf;
    
    printf("All Free\n");
    for(p = garbagecollection_head;p != NULL;p = buf){
        buf = p->next;
        if(p->syu == 'm'){
            printf("メモリ領域pointer=%p開放\n",p->memoryp);
            free(p->memoryp);
        }
        else if(p->syu == 'f'){
            printf("ファイルポインタpointer=%p開放\n",p->memoryp);
            fclose(p->memoryp);
        }
        free(p);
    }
    garbagecollection_head = NULL;
    return 1;
}
/* 
メモリ領域を開放する
*/
int Gcfree(void *ptr){
    Garbage *pre,*p;
    if(garbagecollection_head == NULL) return 0;
    if(garbagecollection_head->memoryp == ptr){
        p = garbagecollection_head;
        garbagecollection_head = p->next;
    }
    else{
        for(pre = garbagecollection_head,p = garbagecollection_head->next;p != NULL;pre = p,p = p->next){
            if(p->memoryp == ptr) break;
        }
        if(p == NULL) return 0;
        pre->next = p->next;
    }
    if(p->syu == 'm'){
        printf("メモリ領域pointer=%p開放\n",p->memoryp);
        free(p->memoryp);
    }
    else if(p->syu == 'f'){
        printf("ファイルポインタpointer=%p開放\n",p->memoryp);
        fclose(p->memoryp);
    }
    free(p);
    return 1;
}
/*
構造体に格納されているデータを表示する関数
*/
void printst(void){
    Garbage *p;
    
    printf("**************************************************************\n");
    
    for(p=garbagecollection_head;p != NULL;p = p->next){
      if(p->syu=='f'){printf("FILE   ");}
      else if(p->syu == 'm'){printf("malloc ");}
      printf("pointer=%p ",p->memoryp);
      printf("size=%d\n",p->size);
    }
    printf("**************************************************************\n");
}





この投稿にコメントする

削除パスワード

No.3420

Re:メモリの一括解放関数
投稿者---kolona(2005/02/11 02:03:28)


>ちょっと面白そうだったので私も書いてみました。
mallocしてからGcに登録するのはめんどくさいのでGcmallocなんて関数を作ってmallocと同時にGc登録が出来るようにしてみました。
アドレスは重複しないのでIDを削除して代わりに使っています。

ポインタの数値はメモリアドレスそのものではないため、ファイルポインタとポインタの数値が重複することがあるのではないか、と思ってIDを設定していたのですが、ファイルポインタとポインタを区別する識別子があるのだから、確かにIDは不要ですね。おまけにchar *pの(*p)の大きさは1でした。ここは数値をそのまま引数にするべきですね。
あかまさんのコードでは、headポインタと、第一要素の間に新しく登録するアルゴリズムでしょうか。確かにこれだとダミーの構造体が不要になりますし、終端処理がすっきりします。勉強になりました。それにGcallocのようにまとめてしまえば、malloc失敗のときのエラー処理も「allfree呼び出してexit() 」とすっきりできます。これは作ってみる価値ありですね。
>もしガーベジコレクションを作ってみたいなら
http://i.loveruby.net/ja/rhg/gc.html
この辺を読むと幸せになれるかも。

見てきました。難しかったので、ガーベジコレクションは卒論が終わってから本格的に勉強します。あんまりプログラミングばかりやっていると先生に怒られそうですから。
夜遅くどうもありがとうございました。


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧




掲示板提供:Real Integrity