Java 运行时数据区:堆(Heap),栈(Stack),方法区(Method)的区别(总结)

版权声明:本文为博主原创文章,同步今日头条号:Java云笔记。转载请附上博文链接: https://blog.csdn.net/weixin_44259720/article/details/88360855

(" ^_^ " 看总结请直接拉到最下面 " ^_^ ")

简单介绍一下,Java 的整个 JVM 占用的内存可分为两个大区:(如下图)

  • 线程共享数据区:线程共享区和JVM同生共死,所有线程均可访问此区域;
  • 线程私有数据区:顾名思义每个线程各自占有,与各自线程同生共死;

堆(heap),栈(stack),方法区(method) 是我们日常接触最多的概念,本篇主要介绍区别。

简述:

1. 堆区::

  • 数据结构:队列优先,先进先出(FIFO),类似于树结构;
  • 内存分配:一般由程序员分配释放,若程序员不释放,程序结束时可能由 OS 回收,分配方式类似于链表(PS:Java 中都是系统 GC,程序员无法进行 GC);
  • 缓存机制:使用二级缓存,生命周期与虚拟机的 GC 算法有关(并不是引用为空就立即被GC),调用速度相对较低;
  • 存储的全部是对象,每个对象都包含一个与之对应的 class 的信息(class的目的是得到操作指令) ;
  • JVM 只有一个堆区(heap),它被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身 ;

2. 栈区::

  • 数据结构:先进后出(FILO)
  • 内存分配:由操作系统自动分配释放,存放函数的参数值,局部变量值等;
  • 缓存机制:使用一级缓存,被调用时通常处于存储空间中,调用后被立即释放;
  • 每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中 ;
  • 每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问; 
  • 栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令); 

3. 方法区::

  • 又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量; 
  • 方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量;

我们通过一个实例,看一看内存是如何分配的:

public class test {                                 // 运行时, JVM 把 test 类的信息都放入方法区    
    public static void main(String[] args) {        // main 方法本身放入方法区。    
        Programmer name = new Programmer("Jimmy");  // name 是引用放到栈区里, Programmer 对象放到堆里面    

        name.print();    
    } 
 
    public class Programmer  {            // 运行时,JVM 把 Programmer 类的信息都放入方法区    
        /** 属性名称 */    
        private String name;              // new Programmer实例后,name引用放入栈区里,name对象放入堆里  
        /** 构造方法 */    
        public Programmer(String name) {  
            this .name = name;    
        }    
        /** 输出方法 */    
        public void print() {             // print 方法本身放入方法区里。   
            System.out.println(name);    
        } 
    }
} 

变量在内存中的分配:

1. 类变量(static修饰的变量,静态变量):在程序加载时系统就为他在队中开辟了内存,堆中的内存地址存放于栈以便于高速访问。静态变量的生命周期 -- 一直到系统关闭。

2. 实例变量(实例化对象):当你使用java关键字new时,系统在堆中开辟并不一定是连续的空间分配给变量,然后根据零散的堆内存地址,通过哈希算法换算为一长串数字以表征这个变量在堆中的“物理位置”。实例变量的生命周期——实例变量的引用丢失后,将被GC列入到可回收名单中,但不是马上回收释放;

3. 局部变量:生命在某个方法或者某段代码里面,执行到他的时候在栈中开辟内存,局部变量一旦脱离作用域,内存立即释放。

堆(heap)和栈(stack)的区别:

1. 栈存放的是基本类型变量和对象的引用,当超出作用域后,栈内存会被释放;堆存放的是new出来的对象和数组;

2. 堆可以动态分配内存大小,生存期也不必高速编译器,java的垃圾回收器会自动收走那些不再被使用的对象数据。存放栈中的数据大小与生存期则必须是确定的,缺乏灵活性。

3. 存取速度方面,栈的速度要比堆快,仅次于直接位于CPU中的寄存器。而堆由于要在运行时动态分配内存,所以存取速度较慢;

4. 栈的数据是可以共享的,比如字面量3等,而堆不可以;

5. 栈是一种线性集合,其添加和删除元素的操作应在同一段完成,栈按照“先进后出”的方式进行处理;堆的对象地址是不连续的,可以随时访问;

更多精彩,请关注我的"今日头条号":Java云笔记
随时随地,让你拥有最新,最便捷的掌上云服务

猜你喜欢

转载自blog.csdn.net/weixin_44259720/article/details/88360855