メモリ管理
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
C/C++の重要な題目であるメモリ管理を
本気を出して1つのトピックにまとめてみたいと思います
かなり長くなる予定なので読む人は覚悟してください
ちなみにVisualC++(以下VC)の環境下での話です。gccとかはわ...
・概要(なぜメモリ管理が必要か?)
・変数の型
・変数のスコープ
・変数の寿命
・ポインタ
・構造体、クラス
・アライメント
・動的なメモリの確保
・placement new
・よくやる間違えと対策
・メモリリーク検出デバック技術
気づき次第+気力あり次第追記・・・
----
* 概要 [#yf007199]
プログラム上での「メモリ」というものが何を意味するのか?
ここでいうメモリというのは
コンピュータ上でデータ(数値、文字列等)をプログラム実行...
メモリにはそれぞれがどの場所に配置されているのかという「...
ありきたりな書き方をするならばアドレスはメモリの住所みた...
アドレスがわかれば、そのアドレスが指すメモリの中身もわか...
たとえば、
0x01番地にはAさんが住んでいる
0x02番地にはBさんが住んでいる
とすると
ここでいう0x01番地(0x02番地)がアドレスでAさん(Bさん...
住所がわかれば、住んでいる人もわかるわけです
また、AさんとBさんが住む場所を入れ替わった時は
0x01番地にはBさんが住んでいる
0x02番地にはAさんが住んでいる
となり
住所(アドレス)をみると住んでいる人(メモリ)も当然入れ...
とりあえずここでは変数にはアドレスとメモリがセットである...
アドレスについてさらに詳しいことはポインタの項目で追記し...
プログラム上でメモリを使いたいとき、変数というものを宣言...
また、このとき
&color(#ff0000){''<<重要>>:変数はメモリとアドレスが...
このことはメモリを管理する上でかなり重要です。
また、メモリ管理をうまくできれば、処理が早くなったり、
さまざまな使い道もできるようになります。
-----
* 変数の型 [#t503e160]
変数というものはアドレスとメモリがセットになっているもの...
また、&color(#ff0000){''どのような用途にメモリが使われる...
C/C++言語では色々な型が使えます
基本的な型では
int型(整数格納用メモリ)
char型(文字格納用メモリ)
float型(浮動小数用メモリ)
double型(倍精度小数用メモリ)
などのほかに
ポインタ(アドレス格納用メモリ:ポインタの項目で後述)
構造体(自分で定義したメモリの格納方式:構造体の項目で後...
クラス(自分で定義したメモリの格納方式+関数のセット:ク...
の変数宣言が使えます
変数毎に確保されるメモリの領域(大きさ)が異なり、
さらに使っている処理系(コンパイラ)などによって異なりま...
sizeof(変数の型)でその変数が何バイトのメモリを使用してい...
たとえば
Visual Studio2005,2008環境下での
C++変数のint型、float型は4バイトになっています。
当然ながら、確保している変数の要領を超えた量は保存できま...
4バイトなら1バイト8ビットなので
2の32乗分の数値が判別できますが
これを超える数値は判別できず、そのような数値を代入した場合
おかしなことになります。
また&color(#ff0000){''constキーワードを変数の型の前につけ...
const int a = 5; // 初期化時のみ代入可能
a = 10; // ←書き換え不能、コンパイルエラー
int b = a; // aのメモリのデータでほかのデータを書き換え...
constキーワードを変数につけることでその変数は書き換えがな...
-----
* 変数のスコープ[#ea28f60c]
&color(#ff0000){''変数のスコープというのはある変数のメモ...
というとわかりにくいと思うので例をあげます
たとえば、C/C++言語お決まりのmain関数(プログラムの開...
ブロック{}(カギ括弧)で挟んで処理をおこなうわけですが・...
ブロックの中で定義した変数はそのブロックの中でしか使えま...
#include <stdio.h>
int main()
{
int a = 10; //int型(整数用メモリ格納型)変数aの宣言
{
int b = 5; //int型(整数用メモリ格納型)変数bの宣言
}// bのスコープの終わり(このブロックをでるとbは使えな...
//a += b; // ←bのメモリは計算に使えない
return 0;
}// aのスコープの終わり
ここでいいたいことは、ブロックの}を抜けたときに
処理計算に変数bのメモリが使えなくなるということです
ブロックで囲まれたところで宣言した変数をローカル変数とい...
また、すべてのブロックの外で定義された変数をグローバル変...
グローバル変数はどの場所からでもその変数のメモリを使うこ...
プログラムコードが長くなってきた場合、
どこで変数の書き変わりが起こったのかわからなくなるので好...
極力、ローカル変数で変数は定義するようにしたほうがよいで...
また、ローカル変数で同名の変数が定義されていた場合、そち...
ちょっと意地悪な例を出します、実行前にどの値が出力される...
#include <stdio.h>
int a = 0; // グローバル変数
int main()
{
int b = a;
printf("%d\n",b);
int a = 5;// ローカル変数
int c = a;
printf("%d\n",c);
{
int a = 10; // ローカル変数
int d = a;
printf("%d\n",d);
}
int d = a;
printf("%d\n",d);
return 0;
}
局所的な計算で関数を作るまでもない処理の場合、
極力ブロックで囲むと変数の寿命が制御できて
コーディングがしやすいかもしれません
また関数などで
#include <stdio.h>
void func(int a)
{
a += 5; // main関数のaとは別物
}
int main()
{
int a = 10;
func(a);
printf("%d\n",a);
return 0;
}
とやっても、main関数のaとfunc関数のaのアドレスが違う(関...
のでmain関数のaの値は変わりません
これの解決策にmain関数のaのアドレスを渡して、
main関数でもfunc関数でも同じアドレスの指すメモリを書き換...
ほかのブロックでも書き換えが行われることになります
変数のアドレス自体を渡すにはポインタを使います(後述)
複数のファイルにまたがって変数の場合
externキーワードを変数の先頭につけます
externは複数のソースファイルにまたがり、共通して使えるこ...
-----
* 変数の寿命[#ea28f60c]
&color(#ff0000){''変数の寿命というのはある変数のメモリが...
次のような&color(#ff0000){''キーワードを変数の型の前につ...
auto 自動
static 静的
&color(#ff0000){''キーワードつけない場合は自動的にautoキ...
ブロック内で宣言されたautoキーワードの変数の場合、ブロッ...
グローバル領域の場合はプログラムが終了するまでが寿命です
たとえば先ほどの例では
#include <stdio.h>
int main()
{
int a; //autoキーワードが省略されているint型(整数用...
return 0;
}// aのスコープの終わり(見えなくなる)かつ変数の寿命(メ...
----
* ポインタ [#g285ff61]
----
* 構造体、クラス [#id45c9b3]
----
* アライメント [#yf007199]
処理系ごとに計算がしやすいという単位が決まっています
たとえば32bitマシンであれば、同時に32bit(4バイト)まで
1回の計算で処理することができます
これがメモリ管理時に困った事態を発生することがあります
(特にネットワーク系、またはメモリ使用量の制限があるとき)
というのは
たとえば32bitマシンにとっては4バイト単位のが計算しやすい...
勝手にVCのコンパイラは(構造体などの)データ型を4の倍数に...
このとき発生するデータの隙間の無駄メモリをアライメントと...
対策としては32bitマシンの場合、
1つめは4バイト単位のデータ型から変数を定義していきパディ...
パディングというのは詰め物という意味でメモリの隙間(アラ...
単位バイト(1バイト)の変数でつめてしまうことです
ただし、この場合処理系ごとに構造体の中身のパディングを変...
もうひとつは#pragma packを使います
#pragma自体も処理系依存ですが
#pragma pack(push,アライメント)を使うことでアライメントを...
また、#pragma pack(pop)で適応範囲を指定してやることもでき...
#pragma packはほとんどのCコンパイラで使えるらしい・・・(...
// アライメント
#include <stdio.h>
typedef struct s1
{
char ch1;
int i1;
} t1;
// アライメントを指定してやる
// 1,2,4,16,32(2の倍数単位)
#pragma pack(push,1)
typedef struct s2
{
char ch1;
int i1;
} t2;
#pragma pack(pop)
int main(int argc,char *argv[])
{
printf("size of t1=%d\n",sizeof(t1));
printf("size of t2=%d\n",sizeof(t2));
return 0;
}
----
* 動的なメモリの確保 [#yd0b6fdb]
----
* placement new [#kfa6d595]
通常、動的なメモリを確保するにはmallocやnewを使いますが
placement newはもとから割り当てられたメモリ領域から必要な...
メモリを確保する方法です
メモリを確保する対象(配列など)をメモリプールとよび
通常の動的確保と違い、すでに割り当てているメモリプールから
空きメモリを取れる場所を探索するため、newと違い高速です。
利点としては、メモリ解放はもとから割り当てられている領域...
newと違い、deleteしなくてもよい(メモリプールが解放される...
また、クラス内変数の別のクラスの配列の初期化を行うことが...
// placement new
#define _CRT_SECURE_NO_DEPRECATE 1 /* VisualC++2005 での...
#include <new>
#include <iostream>
#include <cstring>
char global_area[1000]; // グローバル領域
int main()
{
// グローバル領域に、char10個分の領域を確保して、そこを...
char* p = new(global_area) char[10];
::strcpy( p, "aaaaaaaaa" );
// 同じ結果が出力されることを確認する
std::cout << p << std::endl;
std::cout << global_area << std::endl;
return 0;
} // プログラム終了時にglobal_areaは解放されるのでメモリ...
----
* よくやる間違えと対策 [#x4a71d91]
----
* メモリリーク検出デバック技術 [#r297ab33]
-----
* 投票 [#ea28f60c]
修正・追記の参考したいので
わかりやすかった節に投票をお願いします
#vote(概要[0],変数の型[0],変数のスコープ[0],変数の寿命[0]...
終了行:
C/C++の重要な題目であるメモリ管理を
本気を出して1つのトピックにまとめてみたいと思います
かなり長くなる予定なので読む人は覚悟してください
ちなみにVisualC++(以下VC)の環境下での話です。gccとかはわ...
・概要(なぜメモリ管理が必要か?)
・変数の型
・変数のスコープ
・変数の寿命
・ポインタ
・構造体、クラス
・アライメント
・動的なメモリの確保
・placement new
・よくやる間違えと対策
・メモリリーク検出デバック技術
気づき次第+気力あり次第追記・・・
----
* 概要 [#yf007199]
プログラム上での「メモリ」というものが何を意味するのか?
ここでいうメモリというのは
コンピュータ上でデータ(数値、文字列等)をプログラム実行...
メモリにはそれぞれがどの場所に配置されているのかという「...
ありきたりな書き方をするならばアドレスはメモリの住所みた...
アドレスがわかれば、そのアドレスが指すメモリの中身もわか...
たとえば、
0x01番地にはAさんが住んでいる
0x02番地にはBさんが住んでいる
とすると
ここでいう0x01番地(0x02番地)がアドレスでAさん(Bさん...
住所がわかれば、住んでいる人もわかるわけです
また、AさんとBさんが住む場所を入れ替わった時は
0x01番地にはBさんが住んでいる
0x02番地にはAさんが住んでいる
となり
住所(アドレス)をみると住んでいる人(メモリ)も当然入れ...
とりあえずここでは変数にはアドレスとメモリがセットである...
アドレスについてさらに詳しいことはポインタの項目で追記し...
プログラム上でメモリを使いたいとき、変数というものを宣言...
また、このとき
&color(#ff0000){''<<重要>>:変数はメモリとアドレスが...
このことはメモリを管理する上でかなり重要です。
また、メモリ管理をうまくできれば、処理が早くなったり、
さまざまな使い道もできるようになります。
-----
* 変数の型 [#t503e160]
変数というものはアドレスとメモリがセットになっているもの...
また、&color(#ff0000){''どのような用途にメモリが使われる...
C/C++言語では色々な型が使えます
基本的な型では
int型(整数格納用メモリ)
char型(文字格納用メモリ)
float型(浮動小数用メモリ)
double型(倍精度小数用メモリ)
などのほかに
ポインタ(アドレス格納用メモリ:ポインタの項目で後述)
構造体(自分で定義したメモリの格納方式:構造体の項目で後...
クラス(自分で定義したメモリの格納方式+関数のセット:ク...
の変数宣言が使えます
変数毎に確保されるメモリの領域(大きさ)が異なり、
さらに使っている処理系(コンパイラ)などによって異なりま...
sizeof(変数の型)でその変数が何バイトのメモリを使用してい...
たとえば
Visual Studio2005,2008環境下での
C++変数のint型、float型は4バイトになっています。
当然ながら、確保している変数の要領を超えた量は保存できま...
4バイトなら1バイト8ビットなので
2の32乗分の数値が判別できますが
これを超える数値は判別できず、そのような数値を代入した場合
おかしなことになります。
また&color(#ff0000){''constキーワードを変数の型の前につけ...
const int a = 5; // 初期化時のみ代入可能
a = 10; // ←書き換え不能、コンパイルエラー
int b = a; // aのメモリのデータでほかのデータを書き換え...
constキーワードを変数につけることでその変数は書き換えがな...
-----
* 変数のスコープ[#ea28f60c]
&color(#ff0000){''変数のスコープというのはある変数のメモ...
というとわかりにくいと思うので例をあげます
たとえば、C/C++言語お決まりのmain関数(プログラムの開...
ブロック{}(カギ括弧)で挟んで処理をおこなうわけですが・...
ブロックの中で定義した変数はそのブロックの中でしか使えま...
#include <stdio.h>
int main()
{
int a = 10; //int型(整数用メモリ格納型)変数aの宣言
{
int b = 5; //int型(整数用メモリ格納型)変数bの宣言
}// bのスコープの終わり(このブロックをでるとbは使えな...
//a += b; // ←bのメモリは計算に使えない
return 0;
}// aのスコープの終わり
ここでいいたいことは、ブロックの}を抜けたときに
処理計算に変数bのメモリが使えなくなるということです
ブロックで囲まれたところで宣言した変数をローカル変数とい...
また、すべてのブロックの外で定義された変数をグローバル変...
グローバル変数はどの場所からでもその変数のメモリを使うこ...
プログラムコードが長くなってきた場合、
どこで変数の書き変わりが起こったのかわからなくなるので好...
極力、ローカル変数で変数は定義するようにしたほうがよいで...
また、ローカル変数で同名の変数が定義されていた場合、そち...
ちょっと意地悪な例を出します、実行前にどの値が出力される...
#include <stdio.h>
int a = 0; // グローバル変数
int main()
{
int b = a;
printf("%d\n",b);
int a = 5;// ローカル変数
int c = a;
printf("%d\n",c);
{
int a = 10; // ローカル変数
int d = a;
printf("%d\n",d);
}
int d = a;
printf("%d\n",d);
return 0;
}
局所的な計算で関数を作るまでもない処理の場合、
極力ブロックで囲むと変数の寿命が制御できて
コーディングがしやすいかもしれません
また関数などで
#include <stdio.h>
void func(int a)
{
a += 5; // main関数のaとは別物
}
int main()
{
int a = 10;
func(a);
printf("%d\n",a);
return 0;
}
とやっても、main関数のaとfunc関数のaのアドレスが違う(関...
のでmain関数のaの値は変わりません
これの解決策にmain関数のaのアドレスを渡して、
main関数でもfunc関数でも同じアドレスの指すメモリを書き換...
ほかのブロックでも書き換えが行われることになります
変数のアドレス自体を渡すにはポインタを使います(後述)
複数のファイルにまたがって変数の場合
externキーワードを変数の先頭につけます
externは複数のソースファイルにまたがり、共通して使えるこ...
-----
* 変数の寿命[#ea28f60c]
&color(#ff0000){''変数の寿命というのはある変数のメモリが...
次のような&color(#ff0000){''キーワードを変数の型の前につ...
auto 自動
static 静的
&color(#ff0000){''キーワードつけない場合は自動的にautoキ...
ブロック内で宣言されたautoキーワードの変数の場合、ブロッ...
グローバル領域の場合はプログラムが終了するまでが寿命です
たとえば先ほどの例では
#include <stdio.h>
int main()
{
int a; //autoキーワードが省略されているint型(整数用...
return 0;
}// aのスコープの終わり(見えなくなる)かつ変数の寿命(メ...
----
* ポインタ [#g285ff61]
----
* 構造体、クラス [#id45c9b3]
----
* アライメント [#yf007199]
処理系ごとに計算がしやすいという単位が決まっています
たとえば32bitマシンであれば、同時に32bit(4バイト)まで
1回の計算で処理することができます
これがメモリ管理時に困った事態を発生することがあります
(特にネットワーク系、またはメモリ使用量の制限があるとき)
というのは
たとえば32bitマシンにとっては4バイト単位のが計算しやすい...
勝手にVCのコンパイラは(構造体などの)データ型を4の倍数に...
このとき発生するデータの隙間の無駄メモリをアライメントと...
対策としては32bitマシンの場合、
1つめは4バイト単位のデータ型から変数を定義していきパディ...
パディングというのは詰め物という意味でメモリの隙間(アラ...
単位バイト(1バイト)の変数でつめてしまうことです
ただし、この場合処理系ごとに構造体の中身のパディングを変...
もうひとつは#pragma packを使います
#pragma自体も処理系依存ですが
#pragma pack(push,アライメント)を使うことでアライメントを...
また、#pragma pack(pop)で適応範囲を指定してやることもでき...
#pragma packはほとんどのCコンパイラで使えるらしい・・・(...
// アライメント
#include <stdio.h>
typedef struct s1
{
char ch1;
int i1;
} t1;
// アライメントを指定してやる
// 1,2,4,16,32(2の倍数単位)
#pragma pack(push,1)
typedef struct s2
{
char ch1;
int i1;
} t2;
#pragma pack(pop)
int main(int argc,char *argv[])
{
printf("size of t1=%d\n",sizeof(t1));
printf("size of t2=%d\n",sizeof(t2));
return 0;
}
----
* 動的なメモリの確保 [#yd0b6fdb]
----
* placement new [#kfa6d595]
通常、動的なメモリを確保するにはmallocやnewを使いますが
placement newはもとから割り当てられたメモリ領域から必要な...
メモリを確保する方法です
メモリを確保する対象(配列など)をメモリプールとよび
通常の動的確保と違い、すでに割り当てているメモリプールから
空きメモリを取れる場所を探索するため、newと違い高速です。
利点としては、メモリ解放はもとから割り当てられている領域...
newと違い、deleteしなくてもよい(メモリプールが解放される...
また、クラス内変数の別のクラスの配列の初期化を行うことが...
// placement new
#define _CRT_SECURE_NO_DEPRECATE 1 /* VisualC++2005 での...
#include <new>
#include <iostream>
#include <cstring>
char global_area[1000]; // グローバル領域
int main()
{
// グローバル領域に、char10個分の領域を確保して、そこを...
char* p = new(global_area) char[10];
::strcpy( p, "aaaaaaaaa" );
// 同じ結果が出力されることを確認する
std::cout << p << std::endl;
std::cout << global_area << std::endl;
return 0;
} // プログラム終了時にglobal_areaは解放されるのでメモリ...
----
* よくやる間違えと対策 [#x4a71d91]
----
* メモリリーク検出デバック技術 [#r297ab33]
-----
* 投票 [#ea28f60c]
修正・追記の参考したいので
わかりやすかった節に投票をお願いします
#vote(概要[0],変数の型[0],変数のスコープ[0],変数の寿命[0]...
ページ名: