質問: s i is a;-True i;-"a" ``` メモリ解放のプロセスは、言語側が自動で行ってくれており、プログラマが行わなくてもいい。 静的型付言語だと、このような事は出来ないとします。 極端に言えば、静的型付言語と、動的型付言語は、どんな場合でも、このように変数の型が定まるものであるとします。 頭の中で、このように動的型付言語と、静的型付言語を整理したとします。 しかし、静的型付言語である`Java`では、強制型変換が行われます。また、自動型変換という機能もあります。 この静的型付言語であるはずの`Java`で、メモリが割り当てられているのに、強制的に型が変換されるとすれば、メモリの動きはどのようになるのでしょうか。(強制)という言葉は、解放プロセスもなく、無理やりというニュアンスに思えます。 型が変換された後の型になるのはわかります。しかし、メモリの動きはいったいどうなっているんでしょうか?メモリはのっぺらな配列であると聞きます。そして、静的型付けの場合、最初に割り当てられたアドレスがギュッと詰まっているとします。その時、その中のアドレスの一部が強制的に書き換えられたとき、もし元の領域よりも大きな領域が割り当てられれば、それは何らかのエラーを発生させるのでしょうか?(別の領域と被ると思うからです。)それとも、元のアドレス自体は一旦解放され、新しく別の領域にメモリが割り当てられるのでしょうか?それとも、被ると思われるアドレスを、そのまま大きくなった分だけスライドさせるのでしょうか?元々そんなに詰めた形では割り当てられていないのでしょうか? いずれにせよ、このような事が可能であるとするならば、静的型付言語の中にも、動的型付と言える部分があるんだなと感じます。 メモリにはスタックと、ヒープというのがあり、スタックは整列的。ヒープはランダム的に割り当てられると言います。静的型付言語だとしても、この二つを使い分けて移し合いながらメモリの動的管理を行っているのでしょうか? とすれば、スタックとヒープ両方のメモリが満杯になった時に、なおメモリの領域を要求する時に起るエラーが、スタック・オーバーフローと考えてもよろしいでしょうか? wikipediaによると、結局静的型付と動的型付の境界線は曖昧だ。と知りました。 動的型付の場合は、メモリの解放を自動で行ってくれるため、楽ですし、また任意の場所に割り当てればよいと思いますが、静的型付けの場合、これはプログラマが解放と割り当ての責任を負う。という認識で間違いないでしょうか? 何個も聞いてるので、まとめます。(さりげなく項目が増えています。) ・静的型付言語でも、動的型付が行われれば、メモリはどのように動くのでしょうか。 ・スタックとヒープを使い分けて、メモリの動的管理をしているのですか? ・スタックとヒープ両方の領域が詰まっていてなおメモリの領域を確保しようとすると、スタック・オーバーフローというエラーが起きるのですか? ・静的型付言語の場合、元々静的に割り当てられていたメモリを解放して、別のメモリを割り当てるのは、ユーザーの責任によって管理するもので、動的型付け言語ではない場合は、全てそのようになりますか?(`c`の`malloc`関数というのをよく聞きます。) ・実は言語ごとに異なり、結局のところ、その都度メモリについての扱いを変えるしかないでしょうか。 ・私の頭の中に敷いた理解自体に、どこかおかしいところはありますか? ・もう少し`C`や`C++`などに触れてから出直すべきですか?
回答: 静的/動的型付けと、静的/動的メモリ割り当ては異なる概念なので一緒くたにすると余計に理解ができなくなります。動的型付けを行いたいとき、動的メモリ割り当てがあると楽になるかもしれませんが、動的メモリ割り当てが無くても動的型付けは可能でしょう。 例えば [c](/questions/tagged/c "'c' のタグが付いた質問を表示") の共用体なんてのは動的型付けに使うことができます。 ``` union dynamic_content_type { int64_t IntegralValue; double FloatingValue; }; union dynamic_content_type u; ``` この変数 `u` には整数型の値を格納したり浮動小数点数型の値を格納したりできます。任意の型(の値)を格納することはできないのでこれを動的型付けと呼ぶかどうかは各個人の意見次第だったりしますが。 変数のための記憶域をどう管理するかは全く別の問題で、 * コンパイル時点で変数の寿命が管理できるもの ([c](/questions/tagged/c "'c' のタグが付いた質問を表示") でいう自動記憶域期間) 実装上は、たいていスタック上にとられる + コンパイラが自動的に生成消滅させる命令を作る [c](/questions/tagged/c "'c' のタグが付いた質問を表示") / [c++](/questions/tagged/c%2b%2b "'c++' のタグが付いた質問を表示") + 消滅は garbage collection 任せな [c#](/questions/tagged/c%23 "'c#' のタグが付いた質問を表示") * オブジェクトの寿命をプログラマが管理するもの ([c](/questions/tagged/c "'c' のタグが付いた質問を表示") でいう動的記憶域期間) 実装上は、たいていヒープ上にとられる + プログラマが 100% 管理する義務がある [c](/questions/tagged/c "'c' のタグが付いた質問を表示") / [c++](/questions/tagged/c%2b%2b "'c++' のタグが付いた質問を表示") + garbage collection が頑張ってくれる [c#](/questions/tagged/c%23 "'c#' のタグが付いた質問を表示") / [java](/questions/tagged/java "'java' のタグが付いた質問を表示") * プログラム開始時から終了時まで存在し続けるもの ([c](/questions/tagged/c "'c' のタグが付いた質問を表示") でいう静的記憶域期間) 実装上は、専用領域にとられる + `static` な変数は言語によらずたいていこれ などなどと、各言語によって仕様が異なります。なおスタックやヒープというのが具体的にどんなものなのかはほとんどの言語仕様書で規定していません(言語仕様制定者は、もちろんよくある実装を意識して仕様を定めていますが) なので答えられる質問に答えるとして > > ・実は言語ごとに異なり、結局のところ、その都度メモリについての扱いを変えるしかないでしょうか。 > > > Yes > > ・スタックとヒープを使い分けて、メモリの動的管理をしているのですか? > > > そういう言語処理系もあります(っていうかまあたいていはそうです) > > ・スタックとヒープ両方の領域が詰まっていてなおメモリの領域を確保しようとすると、スタック・オーバーフローというエラーが起きるのですか? > > > スタックとヒープは別領域です。 Windows などだとスタック領域は固定サイズで、ヒープ領域は使うことを許可された残りメモリ(可変サイズ)です。 * [スタックを使い切ったら] ヒープが余っていてもスタックオーバーフローとなります。 * [ヒープを使い切ったら] スタックが余っていても Out of Memory となります。なぜか Out of Heap とは呼ばないようです。 > > ・静的型付言語の場合、元々静的に割り当てられていたメモリを解放して、別のメモリを割り当てるのは、ユーザーの責任によって管理するもので、動的型付け言語ではない場合は、全てそのようになりますか?(cのmalloc関数というのをよく聞きます。) > > > 型付けと記憶域管理は別物ですので質問に意味がありません。 こういう話はコンピュータ内部の実装の話ですので、深く理解したかったら各種 OS なり各種言語なりの内側を知る必要があります。っていうか高級言語ってのはそういう細かいところを知らなくてもプログラムが作れるようにしてくれるものなわけです。現在の [python](/questions/tagged/python "'python' のタグが付いた質問を表示") をただ使うのに飽きたとかでコンピュータの内側を細かく詳しく知りたいのであれば > > ・もう少しCやC++などに触れてから出直すべきですか? > > > C はそういう細かいところを記述するための言語だったりするので、そうなりますね。