小言_互联网的博客

Java内存中的堆和栈

450人阅读  评论(0)

Java内存中的堆和栈

堆(Heap-线程共享)

堆是由Java程序在运行时进行创建的一块内存区域,是被线程共享的一块内存区域。我们创建的对象和数组都保存在 Java的堆内存中,在堆内存中创建的任何对象都具有全局访问权限,可以从应用程序的任何位置进行引用
与此同时,垃圾收集也在堆内存上进行,以释放没有任何引用的对象所占用的内存。由于现代Java虚拟机 采用分代收集算法,因此 Java 堆从 GC 的角度还可以细分为: 新生代(Eden 区、From Survivor 区和 To Survivor 区)和老年代。

栈(Stack-线程私有)

执行一个线程时,会为其开辟一块单独的栈内存,栈内存按照先进先出的顺序来进行管理。每当调用一个方法时,都会在栈内存中为其开辟一块单独的区域,用于保存该方法中的变量值以及对其他对象的引用。当该方法执行结束后,栈内存将会回收为该方法分配的内存区域,当有新的方法需要执行的时候,则可将该区域重新分配给新的方法。同时,与堆内存相比,栈内存的内存空间通常非常小。

比较

  1. 堆内存中的数据是全局共享的,而栈内存中的数据仅能由其对应的线程所使用
  2. 堆内存中存储的是对象,栈内存中存储的是基本数据类型(int,double,char等),对对象的引用。需要注意的是String的本质是一个对象
  3. 栈内存按照先进先出的顺序来进行管理
  4. 栈内存的生命周期是比较短暂的,当其对应的线程执行完毕,该栈内存所占据的空间便会被回收以给其它线程使用。而堆内存的生命周期是从应用程序执行开始一直到结束。
  5. 在Java程序执行的过程中,若遇到栈内存已满时,将引发java.lang.StackOverFlowError。而如果堆内存已满,则将引发java.lang.OutOfMemoryError: 与堆内存相比,堆内存的大小要小得多。

需要注意的是,我们在Java中声明的static类型的全局变量虽然也是全局共享,却不是放在堆内存中的,而是放在方法区中的。同样,方法区也是全局共享的,用于存储被 JVM 加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
可以参考如下的Java内存模型图。

结合具体代码看堆和栈的作用

代码

public class Memory {
	public static void main(String[] args) { 
		int i=1; 
		Object obj = new Object(); 
		Memory mem = new Memory();
		mem.foo(obj); 
	}
	
	private void foo(Object param) { 
		String str = param.toString();
		System.out.println(str);
	} 
}

分析

  1. main方法是程序执行的入口,当执行main方法的时候,Java会创建一个供main线程所使用的栈内存,并为main方法单独开辟一块区域用于存放main方法中的局部变量。
  2. 执行int i =1的时候,会将常量保存到main方法的栈内存中。而Object obj = new Object()Memory mem = new Memory()则是创建了两个对象。对象保存到堆内存中,栈内存保存的只是对其的一个引用。
  3. 执行到mem.foo(obj)的时候,java程序知道这里将会执行一个新的方法,于是会在main线程的栈内存中再开辟一块空间,用于单独存放foo方法的局部变量,然后便进入foo方法。这里需要注意的是Java中的值传递。如果传入foo方法的是一个常量值,则会在foo方法中将其单独拷贝一份出来,比如:若往foo方法传了变量i,但是变量i在main方法和foo方法之间是不共享的(除了全局变量),因此在foo方法中也会单独拷贝一份i变量出来。而传递的若是一个对象,则会产生一个新的引用指向堆内存中的对象。于是foo方法的栈内存中会产生一个新的引用指向Object对象。
  4. String str = param.toString()会将Object对象param转为为一个字符串(字符串对象),然后将其放入字符串常量池中,字符串常量池同样也是在堆内存中,因为其本质还是对象。
  5. 当foo方法执行完毕以后就会将在栈内存中分配给foo方法的内存空间进行回收。
  6. 当main方法也执行完毕以后,程序到此结束,分配给main方法的的栈内存会被释放,给main线程的栈内存也会被释放,所有被占用的内存也都会被释放。


foo方法执行完毕以后则会将其从栈内存中出栈,为其分配的内存区域也随之被回收。当该线程执行完毕以后,该线程对应的栈内存则会被释放。

参考链接
Java Heap Space vs Stack – Memory Allocation in Java


转载:https://blog.csdn.net/qq_42799615/article/details/105919063
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场