Java中堆和栈的区别?

主要区别:

  • 从存储角度来看,堆内存主要用于存储实例对象和JRE classes,栈内存用于存储基本变量和对象的引用。
  • 从存取速度来看,栈存取速度快,堆区存取比较慢,因为要在运行时动态分配内存,存取速度较慢。
  • 从线程角度来看,每个线程都有一个自己的JAVA栈,所有线程共享一个堆。在JVM中,内存被分为线程栈区和堆区。
  • 从GC来看,栈区GC比较频繁,堆区GC不频繁。

详细比较:

  • 堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
  • 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据在多个线程或者多个栈之间是不可以共享的,但是在栈内部多个值相等的变量是可以指向一个地址的。

Java中堆和栈的区别?_第1张图片

Java 堆栈内存分配(代码分析)

 Java 堆内存空间

  • Java程序运行时使用java Heap 内存为对象以及JRE类分配内存, 不论我们在何时创建何种类型的对象, 他总是在堆内存中创建的。
  • Java 垃圾收集器运行在堆内容空间, 释放那些没有任何引用的对象所使用的内存。 在堆内存空间创建的任何对象都具有全局访问权限, 并且可以从程序的任何位置引用。

 Java 栈内存空间

  • Java 栈内存空间用于执行线程, 栈内存始终遵循LIFO(Last-in-first-out) 顺序, 每当一个方法被执行, 会在栈内存中创建一个新的block 用于保存在函数中定义的基本数据类型变量以及对象的引用变量。
  • 当方法结束时, this block 改变它的状态为未使用并且可用于执行下一个方法。
  • 堆内存大小与堆内存相比非常少。
public class HeapStackTestMemory {

    public static void main(String[] args) {                 //Line 1

        int i = 1;                                           //Line 2

        Object obj = new Object();                           //Line 3

        HeapStackTestMemory mem = new HeapStackTestMemory(); //Line 4

        mem.foo(obj);                                        //Line 5

    }                                                        //Line 9

    private void foo(Object param) {                         //Line 6

        String str = param.toString();                       //Line 7

        System.out.println(str);

    }                                                        //Line 8

}

参考上面的java 程序, 下图显示了stack Heap 内存空间的使用情况

Java中堆和栈的区别?_第2张图片

执行程序的步骤

  • 一旦我们开始运行程序, 它会把所有的运行时类加载到堆内存空间, 在 Line 1 行找到main() 方法, Java Runtime 创建由main() 方法线程使用的栈内存空间。
  • 在第二行 我们创建了原始数据类型的局部变量, 所以它将被存储在main() 方法的栈内存空间。
  • 在第3行我们创建了一个Object 类型的对象, 所以它被创建在Heap 堆内存空间中 并且 Stack 栈内存空间包含对它的引用, 当我们在第4行中创建Memory 对象时, 会发生类似的过程。
  • 现在我们在第5行调用foo() 方法, 此时会在stack 栈创建一个block 供foo() 方法使用。
  • Java 是通过值传递, 在第6行, 会在foo() 栈中创建一个对Object 对象的新的引用。
  • 在第7行 , 一个string 类型的对象被创建, 此时 会在foo() 栈内存中创建它的一个引用 str。
  • foo() 方法在第8行执行完毕, 此时, 程序会释放stack 栈内存中为foo() 方法分配的栈内存空间。
  • 在第9行, main() 方法执行完毕, 为main()方法创建的堆栈内存被销毁, 此时 这个java 程序结束运行, Java Runtime 会释放所有的内存。

 Java Heap Difference with Stack Memory Space

  1. 堆内存属于java 应用程序所使用, 栈内存属于线程所私有的, 它的生命周期与线程相同
  2. 不论何时创建一个对象, 它总是存储在堆内存空间 并且栈内存空间包含对它的引用 . 栈内存空间只包含方法原始数据类型局部变量以及堆空间中对象的引用变量
  3. 在堆中的对象可以全局访问, 栈内存空间属于线程所私有
  4.  jvm 栈内存结构管理较为简单, 遵循LIFO 的原则, 堆空间内存管理较为复杂 , 细分为:新生代和老年代 etc..
  5. 栈内存生命周期短暂, 而堆内存伴随整个用用程序的生命周期
  6. 二者抛出异常的方式, 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常, 堆内存抛出OutOfMemoryError异常

 

 

 

 

 

你可能感兴趣的:(Java面试)