Jvm内存分配举例

2019, Feb 18    

JVM内存分配举例

我们从变量的作用域角度去分析这个问题。

  • 按作用域划分变量
    • 局部变量
    • 全局变量(又叫成员变量)
      • 类变量(静态变量)
      • 实例变量
局部变量

在方法中声明的变量,即该变量是局部变量,每当程序调用方法时,系统都会为该方法建立一个方法栈,其所在方法中声明的变量就放在方法栈中,当方法结束系统会释放方法栈,其对应在该方法中声明的变量随着栈的销毁而结束,这就局部变量只能在方法中有效的原因。

在方法中生明的变量可以是基本类型的变量,也可以是引用类型的变量

(1)当声明是基本类型变量的时,其变量名及值(变量名及值是两个概念)是放在方法栈中

(2)当声明的是引用变量时,所声明的变量(该变量实际上是在方法中存储的是内存地址值)是放在方法的栈中,该变量所指向的对象是放在堆内存中的,如果该变量所指向的是字面量就放到方法区的运行时常量池中

全局变量

在类中声明的变量是成员变量,也叫全局变量,放在堆中的。

同样在类中声明的变量即可是基本类型变量 也可是引用类型变量

(1)当声明的是基本类型变量且:

​ (1.1) 如果被static修饰为静态变量,其变量名和变量值放在方法区(no-heap)中

​ (1.2)如果是实例变量,其变量名及变量值一般放在堆内存中

(2)当声明的是引用类型变量且:

​ (2.1) 如果被static修饰为静态变量,声明的变量放在方法区中,该变量所指向的对象在堆中,如果变量所指向的对象是字面量就放在方法区的运行时常量池中

​ (2.2) 如果是实例变量,声明的变量放在堆中,该变量所指向的对象在堆中的另一个地方,如果变量所指向的对象是字面量就放在方法区的运行时常量池中

总结:其实就是注意两点,1)new 出来的对象在堆中;2)静态变量在方法区中;3)字面量在方法区的运行时常量池中;4)基本数据类型没有引用的概念

举例

// 局部变量
1
public void m1() {
	int i = 1; // i,1在栈中
}

// 局部变量
2
public void m1() {
	Object i = new Object(); // i在栈中,new Object()在堆中
	String s = "hello"; // s在栈中,"hello"在常量池中
	String s1 = new String("hello"); // s1在栈中,new String("hello")在堆中
}

// 全局变量
1.1
public Class C {
	static int i = 1; // i也是在方法区中, 1也在方法区中
}

1.2
public Class C {
	int i = 1; // i,1在堆内存中
	Object i = new Object(); // i在堆中,new Object()在堆中
	String s = "hello" // s在堆中,"hello"在常量池中
}

2.1
public Class C {
	static Object i = new Object(); // i方法区中,new Object()在堆中
	static String s = "hello"; // s在方法区中,"hello"在方法区的运行时常量池中
}

2.2
public Class C {
	Object i = new Object(); // i在堆中, new Object()在堆中
	String s = "hello"; // s在堆中,"hello"在方法区的运行时常量池中
}
参考

static allocation in java - heap, stack and permanent generation

Java Stack and Heap: Java Memory Allocation Tutorial