ホームページ >Java >&#&チュートリアル >Javaのメモリ機構を図解で詳しく解説(コード付き)
Javaはメモリをスタックメモリとヒープメモリの2種類に分けます。関数内で定義されているいくつかの 変数 および オブジェクト の reference 変数は、すべて関数のスタック メモリに割り当てられます。 変数がコード ブロックで定義されている場合、Java はオンになります。スタック この変数にメモリ領域を割り当てます。変数のスコープを超える場合 (たとえば、関数 A で関数 B を呼び出し、関数 B で変数 a を定義し、変数 a のスコープは関数 B のみであり、関数内で実行されます)。 B その後、変数 a は自動的に破棄され (変数 a に割り当てられたメモリはリサイクルされます)、Java は変数に割り当てられたメモリ空間を自動的に解放し、そのメモリ空間はすぐに他の目的に使用できるようになります。 ヒープメモリは、new
によって作成されたメモリ配列を格納するために使用され、ヒープに割り当てられたメモリは、Java仮想マシンの自動ガベージコレクタによって管理されます。 ヒープ内に配列またはオブジェクトを生成した後、スタック内の特殊変数を定義して、スタック内の変数の値がヒープ メモリ内の配列またはオブジェクトの最初のアドレスと等しくなるようにすることもできます。スタック内の変数は、配列またはオブジェクトの参照変数になります。 スタック内の変数を使用して、プログラム内でヒープ内の配列またはオブジェクトにアクセスできます。参照変数は、配列またはオブジェクトに名前を付けるのと同じです。物体。 参照変数は、定義時にスタックに割り当てられる通常の変数であり、プログラムが他のスコープ外で実行された後に解放されます。配列とオブジェクトはヒープ内に割り当てられます。new によって生成された配列またはオブジェクト ステートメントが配置されているコード ブロックの外でプログラムが実行された場合でも、配列とオブジェクトによって占有されていたメモリは解放されません。配列とオブジェクトを指す参照変数が存在しない場合、それらはガベージとなり、後で不定の時点でガベージ コレクターによって収集 (解放) されます。これは、Java がより多くのメモリを消費する理由でもあります。実際、スタック内の変数はヒープ メモリ内の変数を指します。これは Java のポインタです。 コード例 Demo1: 単一オブジェクトの作成
class Person { String name ; int age ; public void tell() { System.out.println("姓名:"+name+",年龄:"+age); } } public class Demo1 { public static void main(String[] args) { Person per = new Person() ; } }上記のプログラムでは、インスタンス化プロセス中に、スタック メモリとヒープ メモリを含むメモリ内の領域を解放する必要があります。引数のメモリ割り当ては、スタックメモリに格納されるのはヒープメモリ空間
のアクセスアドレスであり、属性名や年齢などのオブジェクトの具体的な内容はヒープメモリに格納されます。 per オブジェクトはインスタンス化されただけで特定の値が割り当てられていないため、デフォルト値が設定されています。 stringのデフォルト値は
null、int型のデフォルト値は0です。前述したように、ヒープ メモリ空間は new キーワードを使用して開く必要があります。
コード例デモ2: 複数のオブジェクトの作成
class Person {
String name ;
int age ;
public void tell() {
System.out.println("姓名:"+name+",年龄:"+age);
}
}
public class Demo2 {
public static void main(String[] args) {
Person per1 = new Person() ;
Person per2 = new Person() ;
per1.name="张三" ;
per1.age=30 ;
per2.age=33 ;
per1.tell();
per2.tell();
}
}
Key概念: クラスは配列と同様、参照型です。参照型とは複数のスタック メモリが同じヒープ メモリを指すことができるということを、参照渡しの簡単な例を見てみましょう。
コード例 Demo3: 1 を渡すオブジェクト参照
class Person { String name ; int age ; public void tell() { System.out.println("姓名:"+name+",年龄:"+age); } } public class Demo3 { public static void main(String[] args) { Person per1 = new Person() ; Person per2 = per1 ;//-------注意-------- per1.name="张三" ; per1.age=30 ; per2.age=33 ; per1.tell(); per2.tell(); } }
プログラムの実行結果は次のとおりです:
プログラムの実行結果から、 2 つのオブジェクトの出力内容が同じであることがわかります。 . 実際には、1つのヒープメモリ空間の使用権を複数のスタックメモリ空間に移すことを指します。 このプログラムのメモリ割り当て図は、各スタックメモリ空間で変更できます。は次のとおりです:
图1-3 对象引用的传递内存分配
图1-3 对象引用的传递内存分配(续)
注意:上述实例中对象per2没有堆内存空间,这是因为对象per2只进行声明操作,也没有进行实例化操作。只是使用new关键字,实例化以后才会有堆内存空间
代码实例Demo4:对象引用传递2
class Person { String name ; int age ; public void tell() { System.out.println("姓名:"+name+",年龄:"+age); } } public class Demo4 { public static void main(String[] args) { Person per1 = new Person() ; Person per2 = new Person() ; per1.name="张三" ; per1.age=30 ; per2.name="李四" ; per2.age=33 ; per2=per1 ;//-----注意---- per1.tell(); per2.tell(); } }
上述运行程序结果为:
从程序的输出结果可以发现跟Demo3差不多。不过内存分配发生了一些变化,具体如下所示:
图1-4 (垃圾对象)的产生
注意点:
1.Java本身提供垃圾收集机制(Garbage Collection,GC),会不定期释放不用的内存空间,只要对象不用了,就会等待GC释放空间,如上面堆内存中的name="李四";age=33。
2.一个栈内存只能指向一个堆内存空间,如果要想指向其他堆内存空间,则必须先断开已有的指向,才能分配新的指向。
Java中常见的内存区域
在Java中主要存在4块内存空间,这些内存的名称及作用如下:
1.栈内存空间:保存所有对象的名称。
2.堆内存空间:保存每个对象的具体属性内容。
3.全局数据区:保存static类型的属性值。
4.全局代码区:保存所有的方法定义。
以上がJavaのメモリ機構を図解で詳しく解説(コード付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。