質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

6回答

7498閲覧

ゲームプログラミングにおけるメモリ管理とは??

tiwatiwa

総合スコア70

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

4グッド

8クリップ

投稿2016/03/13 13:29

ゲームプログラミングの本やウェブ上の情報を見ていると、「メモリ管理」という項目が設けられていることが多々あるのですが、メモリ管理は具体的にどういうことをやることなのでしょうか?
内容が難しく抽象的で毎回何かしらの理解できないことがあって読み進められません。

ゲームプログラミング限定ではなく、組み込み系におけるメモリ管理など分野は何でもいいので、メモリ管理の簡単で具体的な説明をよろしくお願いします。

kobaya_c, norm, BeatStar👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答6

0

「メモリ管理」とだけ言われても文脈によってどういうことを指すのかが変わりますし、言語によっても違ってきますから、一言で説明するのは難しいですね。

  • メモリの確保/解放を管理する。

いわゆる動的メモリ確保のことで、単にメモリ管理といった場合はこれを指す場合が多いと思います。必要なときに必要なサイズのメモリ領域を確保し、いらなくなったら解放するという仕組みですね。
C/C++ではmalloc/freeなどの関数が用意されていますし、C++にはnew/deleteという命令もあります。
Java/C#ではメモリ確保とはnewでオブジェクトをインスタンス化することですが、解放はガベージコレクションという仕組みで知らないところで勝手にやってくれるのでプログラマーがあまり意識することはないかもしれません。ただし、ガベージコレクションの仕組みを理解していないと、消費メモリが増えすぎたり、不定期にカクッと一瞬動きが止まったりなどということが起こるかもしれません。

C/C++の場合はメモリを直接いじれるという特性から、標準のメモリ管理機能を使わずに、より高速に動作する独自のメモリ管理機能を実装するということはよくあります。

  • メモリを安全/確実に解放する。

これはC/C++では重要なテーマとなります。確保した領域を解放し忘れると「メモリリーク」となり、無駄にメモリを消費することになり、最悪システムが不安定になったりします。そうならないようにC++ではスマートポインタという仕組みが考案されていて、STLにもその機能が提供されています。
また、「コンテナ」とよばれるメモリの確保/解放を自動で行う機能を持ったクラスも提供されています。

  • メモリ消費量を管理する。

最新のゲーム機はPC並のメモリ搭載量ですが、携帯ゲーム機や安いスマホなどはメモリ搭載量が少ないので、「メモリの無駄遣い」をしないように心がける必要があります。例えば画面上に表示できるキャラは○○体まで、などというような制限を付けて、メモリ消費を一定以下に収まるように管理します。その際、確保/解放とも絡めて、あらかじめ必要な分だけメモリを確保しておき、それを使い回すというテクニックもあります。
これはゲームだけでなく、メモリ搭載量に制限のある組み込み機器などでも重要なテーマです。

投稿2016/03/13 15:02

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiwatiwa

2016/03/13 15:32

回答ありがとうございます! 知りたかったことがドンと返ってきた感じで非常にありがたいです。 >「メモリ管理」とだけ言われても文脈によってどういうことを指すのかが変わりますし、言語によっても違ってきますから、一言で説明するのは難しいですね。 分野や言語、使いどころを絞ると、回答が返ってこないことがあるので大雑把な質問をするようにしました。応えにくくなってしまったのであれば申し訳ないです;; メモリ管理についてですが、最後の「メモリ消費量を管理する」は、具体的にどういうことを指すのでしょうか? (設計段階で、一度に表示するキャラやマップの数を制限したり、マップによって読み込むキャラを制限したりすること?) また、「メモリ管理」は「具体的なメモリ管理のモジュールを設計・実装すること」ではなくて、「メモリ解放を気を付けたり、無駄にメモリを消費したりしないように、メモリについて理解して、使いこなすこと」を指していると認識してもいいのでしょうか?
catsforepaw

2016/03/13 16:00

> (設計段階で、一度に表示するキャラやマップの数を制限したり、マップによって読み込むキャラを制限したりすること?) そうですね、設計段階というのも大事ですが、例えば、マップ上には100人存在するけど、実際に画面に表示できるのは操作キャラの近くの10人までにして、他のキャラが近づいて10人を超えたら、遠いキャラを画面から消す(その分の領域を解放する)、などという制御もあるかと思います。 > また、「メモリ管理」は「具体的なメモリ管理のモジュールを設計・実装すること」ではなくて、「メモリ解放を気を付けたり、無駄にメモリを消費したりしないように、メモリについて理解して、使いこなすこと」を指していると認識してもいいのでしょうか? 基本的にはそれで合っています。ほとんどの場合、提供されているメモリ管理機能をどう使いこなすかというのが重要なテーマとなります。自分でメモリ管理モジュールを設計・実装することは、よほどのこと、例えば、極限まで処理速度を追求するとか、メモリ搭載量が少なすぎてVRAMなども使ってぎちぎちに詰め込まないと入らないとか(組み込み機器ではよくある)、そういう事情がない限り必要ないと思います。
guest

0

ベストアンサー

###クライアントでのメモリ管理
クライアント、つまりアプリ側でのメモリ管理というなら、やはりオブジェクトの生成と破棄になると思います。
例えばシューティングゲームで大量の弾を発射する度に、newしてメモリ確保して弾オブジェクトを生成して、敵に当るか画面外に消えたらdeleteして、なんて真似をしていたらすぐにガベージコレクションが走ってしまいます。
ガベコレの無い言語であっても、newしてメモリ確保する際のシステムコールは馬鹿にならない程思いです。
ゲームは60FPSや30FPS固定で動作することが前提で作られているものが多いです。
しかし、ガベコレが走ってしまったり、1フレーム内の処理が重くなってしまうとFPSを固定することができなくなります。
そうなるとフレーム落ちが発生してしまい、キャラが瞬間移動したり、当っているはずの弾が敵をすり抜けたり、とゲームとして成立しなくなってしまいます。
そうならないために、シューティングゲーム等では1度に表示する弾の数だけゲーム開始前に全てプールに確保してしまいます。

C#

1Queue<Bullet> pool = new Queue<Bullet>(); 2for(int i = 0; i < 1度に表示する最大数; i++) 3{ 4 pool.Enqueue(new Bullet()); 5}

そして、発射の際に先に確保しておいたプールの中から使っていないものを一つ取り出し、アクティブな状態にして表示させます。

C#

1Bullet bullet = pool.Dequeue(); 2bullet.実際に使えるようにする処理

敵に当ったり、画面外に消えるとそれを削除して、元のプールに戻します。

C#

1bullet.使い終わった状態にする処理 2pool.Enqueue(bullet);

こうすることで、ガベコレを防いだり1フレーム内のシステムコールをなるべく減らして処理を軽くすることでFPSを安定させます。
このように、ゲーム内では無限に湧いているように見える弾や敵キャラなども、1度確保したメモリを使いまわして実現しています。
###サーバでのメモリ管理
MMO等のサーバでもオブジェクトの生成、破棄をさせないで、ガベコレを防ぐという考え方は一緒ですが、もう一つ重要なメモリ管理があります。
それは1サーバで同時にログインするキャラ数分の、1キャラが消費するメモリをサーバ立ち上げ時に全て確保しないといけないということです。
1キャラが消費するメモリとは、そのキャラが持っているアイテム等のことです。
これを行っていないと、ログインは出来たけどアイテムで使用するメモリが確保できず、誰かがアイテムを使用してサーバのメモリ上から消えてくれない限り、アイテムを使用することができなくなってしまいます。

投稿2016/03/15 06:25

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiwatiwa

2016/03/16 14:05

回答ありがとうございます! クライアントとサーバに分類しての説明がわかりやすかったです。 この回答の「プール」という言葉でいろいろ検索をした結果、「メモリプール」にたどり着けました!次は実装方法を調べてみます。
guest

0

C 言語ですが、ずーっと昔に、 malloc がメモリ確保時に確保するヘッダの16バイト節約のために、自前のメモリ管理モジュールを作りました。

c

1 2struct list_t { 3 list_t *p, *n; 4 size_t size; 5 char rsv[10]; 6}; 716bit os なのでこれで16バイトかつ16バイトアラインメント。 8このヘッダの直後に、malloc で指定した大きさの16バイト整合した大きさのメモリが続きます。 9malloc(20); とか確保すると、ヘッダ含めて実際には48バイトの領域が取られ、未使用領域が分断されて、 1022バイトできます。この分断された使われない領域のために、細かいメモリ確保を繰り返すと実際のメモリ 11容量よりも少ないところで out of memory が出たりします。 12 13 なので、一度に確保可能な最大を予め確保し、自前のメモリ管理で管理しました。 14struct list_st { 15 list_st *p,*n; 16 size_t size; 17 char data[0]; 18}; 19アラインメントは、dword つまり4バイト整合とし、char data[0]4nの可変サイズになります。 20gcもどきとして、再利用キュー、my_malloc 時は、再利用キューに指定サイズ以上の領域があれば、 21そこから、無ければ大きい場所から新しく切り出し、my_free時は、再利用キューに登録して終わり。 224n 整合なので 下2ビットは無視できるので、一度に確保可能な最大確保量は、256kb になります。

誰でも少ない資源を効率良くと考えると行き着く先はこんな感じになるかと。昔はos のメモリ管理情報が
公開されてたので細かいメモリ確保、開放が頻繁な場合、こういう手を独自実装で高効率化を考える人は
自分以外にもいたはずです。
p,n は双方向リストです。

投稿2016/03/16 09:08

ipadcaron

総合スコア1693

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiwatiwa

2016/03/16 14:07

回答ありがとうございます。 具体的な説明でなんとなくイメージがつきました。 自分もC++での実装をやってみます!
guest

0

昔の体験談になります。

◆断片化を小さくに抑えるため、インスタンスの生成順とは逆順に開放を行う。
たとえばアクション ゲームで

  1. ステージ
  2. メインプレーヤ
  3. 敵プレーヤ

の順に読み込んでいる場合、
ステージ移動の際に前のステージを開放を行いして新しいステージを読み込んだ際に、
新しいステージの方が大きかった場合、
前のステージの領域は使われず、後ろのほうに確保されます。
この状態が繰り返されて使われない領域が増えていく状態が断片化になります。
この断片化を防ぐため、
・読み替えの頻度の低い順に読み込む様にする
・最初に読み込んだ項目を読み直す際、後に読み込んだ項目も開放して読み直す。
を行いました。

尚、最近のJava VMなどではメモリ コンパクション機能があるため、
メモリリークだけでなく、断片化に対しても効果が期待できます。

が、配列は連続したメモリ領域が必要になるのは今でも変わらないため、
特にバイナリを読み込む際には依然注意が必要です。

◆メモリを複数実装しているハード
どのメモリに確保するのかを指定することが出来たハードだったため、
Aのメモリに何を読み込むか
Bのメモリに何を読み込むか
それぞれのメモリの領域を超過しないか
などを計測・調整を行いました。

◆外部モジュール化
実行ファイルもメモリに読み込まれ実行されます。
巨大なプログラムでは、それだけメモリを圧迫することになりますが、
処理の中必要になるのはなかなか一部になります。
そのため、外部モジュールにして動的に読み分け、
リソースと同様にプログラム自体も必要なものだけ読み込む様にします。
Javaではクラスローダーなどで実現している機能の中では、
この効能を期待しているものが今でもあると思います。

◆リソースのライフサイクルの管理
JavaなどのGC系言語でもメディアリソース(画像)はGC対象外であることがあります。
またメディアリソースは容量もでかく、メモリを圧迫しやすいですが、
読み込み時間も長くなるため、先読みを行い長い間使ったりします。
リソースの内容をいくつか分類して、メモリが枯渇しない程度に、
頻繁に再読み込みが発生しない様にライフサイクルを調整行います。

以上、一部脱線しているものもあるかと思いますが、昔の体験談になります。

投稿2016/04/07 16:58

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

もしメモリが管理されていなかった場合PCは手当たり次第メモリにデータを書き込むことになり書きむ場所に保存されているデータが存在していた場合そのデータは消えてしまいますよね。

これを防ぐために保存するデータのメモリをロックしておくわけです。静的な型付け言語では,あらかじめ実行前に使うメモリの容量が解っている静的なデータはプログラムが実行される前にコンパイラがメモリを確保できるか調べて確保してくれますが,プログラムが実行する人の操作でデータのサイズが変わるような動的なデータはあらかじめどれくらいのメモリを使うかということをプログラムが判断することができません。

なので,メモリのアドレスを保存しておける領域を作って,データが生み出される時に確保されたメモリのアドレスの値を保存することで管理しているわけです(Cはこのメモリのサイズもデータが生み出される時にデータのサイズを計算してmallocという関数を使ってメモリを確保しなければいけませんでした)。

しかし,この保存したアドレスの値を消去したところで,そのアドレスが指し示しているメモリの場所は明示的に解放されないのです。もしこのメモリが解放されていないまま,プログラムを回し続けるともう使われていないデータが蓄積されてしまい,色々よくないことが起きます(例えばメモリの使用率が100%を超えるとプログラムがクラッシュして実行中の処理が止まったりします)。なのでメモリを解放する処理をプログラムに書く必要があり,どのタイミングでメモリを解放すべきかということの理解がコンピュータのパフォーマンスを考える上で重要なのです。

メモリの解放をいちいちコードに書くのは面倒なので,最近のプログラミング言語は自動でメモリを解放してくれる機能がついているようなものもありますが,言語仕様でメモリがどのように確保され解放されるか知っておくことは,それをイメージしながらプログラミングすることで,無駄がなく早いコードを書くことにもつながります。

基本的にオブジェクトのインスタンスは動的メモリ確保をするデータだと思ってください(何個生み出されるか実行前にわからないため)。

ゲームプログラミングはこのオブジェクトのインスタンスをよく使うことになり,それぞれを使う時には,そのオブジェクトが他のオブジェクトに使用されているかどうかという参照カウントという値を使用することが多いです。これはスマートポインタという仕組みがよく使われます。オブジェクトが生み出されて使われるごとに参照カウントを+1して,使い終わると値を-1減少させます。参照カウントが0になったらオブジェクトのデストラクタが起動するという仕組みになっています。

メモリの自動解放はこのような単純な仕組みになっていますのでメモリが解放できずに困った時は,自分で書いて直したりパフォーマンスを上げることもできるようになります。

投稿2016/03/13 14:06

編集2016/03/13 14:24
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiwatiwa

2016/03/13 14:49

回答ありがとうございます! つまり、メモリを壊さないようなコーディングができれば、それがメモリ管理の実装されているプログラムだということでいいのでしょうか? 具体的には、 ・mallocやnewによるメモリ確保&解放 ・スマートポインタやガベージコレクションなどのメモリリーク防止機能 ・無駄にメモリを使わないような管理機能の実装 などを行うことがメモリ管理ということでしょうか??
guest

0

こんにちは。

確かにググッてみたら、中々ハードな説明が多いですね。

C言語の場合、malloc()でメモリを獲得してfree()で開放することはご存知ですか?
そのmalloc()やfree()の中の人がやっていることがメモリ管理です。

投稿2016/03/13 13:43

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiwatiwa

2016/03/13 14:50

回答ありがとうございます。 >そのmalloc()やfree()の中の人がやっていることがメモリ管理です。 この1文がよくわからないです。 mallocの中の人がやっていること?とは何のことでしょうか?
Chironian

2016/03/13 14:56

ああ、ごめんなさい。簡単に書きすぎました。 malloc()も当然ですが、プログラムでできています。そのプログラムが行っていることがメモリ管理です。malloc()やfree()の機能からなんとなく見えてこないですか?
tiwatiwa

2016/03/13 15:15

つまり、mallocやfreeを使うことがメモリ管理ということですね。 回答ありがとうございました。
Chironian

2016/03/13 15:29

例えば、図書館の司書さんたちは図書館にある本を管理していますね。 tiwatiwaさんが図書館へ行って本を借りたり返したりしたとしても、「本を管理している」わけではないと思います。 これと同じでmallocやfreeを使うこと=メモリ管理というわけではないです。 イメージ的には、図書館の司書さんたちが本を管理しているように、mallocやfreeはメモリを管理していると言っても良いと思います。 貸し出したことを記録しておき、返却されたらその記録を返却済とし、元の場所へ戻して次の貸出に備えます。
tiwatiwa

2016/03/13 15:57

つまり、司書さんが本を管理するために図書管理システムを使う、司書さんが貸し出し履歴を管理するために貸し出し履歴管理システムを使うような感じで、 自分のプログラムに合ったメモリ管理システムを作って、それを使ってメモリを管理することがメモリ管理ということでいいのでしょうか? 何度もすみません;; 理解できなくて申し訳ないです。
Chironian

2016/03/14 01:56 編集

図書館の司書さん達に当たるものがmallocやfreeですが、mallocやfree自身に該当する機能をアプリケーション・プログラムのプログラマが開発するケースは多くはないです。 特に中間言語方式(JavaやC#)の言語でそれを行うことは皆無に近いと思いますので、それらの言語によるプログラミングの説明で「メモリ管理」の項目が特に設けられている状況があまり想像できません。もし、ウェブにそれがあるようでしたら、URLを教えて頂けませんか? 別の視点に気が付きました。 図書館から借りた本を借りた人はその本を「管理」してますね。どこの図書館から借りたのか、とか、貸出期限に注意を払い期限内に返却する程度の「管理」はしていると思います。 tiwatiwaさんが気にされている「メモリ管理」は、メモリを借りた側がちゃんと返すように管理しなさいと言う話のような気がしてきました。 CやC++では借りたものは意識して返さないと「メモリ・リーク」します。そのようなプログラムを長時間走らせているとメモリ不足になり、多くは異常停止します。借りたものを返さないのですから、いつか枯渇しますよね。当たり前です。 JavaやC#はいちいち返さなくても使ってなければ勝手に回収していくという、使う側の管理負担を下げる仕組みが導入されてます。と言っても、使っている「フリ」をしてしまうとメモリ・リークしますので、その辺のことが書かれているのかも知れません。
tiwatiwa

2016/03/16 14:02

>特に中間言語方式(JavaやC#)の言語でそれを行うことは皆無に近いと思いますので、それらの言語によるプログラミングの説明で「メモリ管理」の項目が特に設けられている状況があまり想像できません。もし、ウェブにそれがあるようでしたら、URLを教えて頂けませんか? 今回はC++での実装を考えていて、CとC++で本を読んだり検索したりしていました。JavaやC#は回答の幅を広げられれば、と思ってとりあえずタブに入れていただけになります。 自分が考えていたメモリ管理は、皆さんからの回答をもとにいろいろ調べてみると、「メモリプール」のことみたいです。Chironianさんの回答の通りだと思います。 メモリプールの実装について調べることにします。 回答ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問