[Java]Java的堆内存和栈内存解析--举例进行内存分析

Posted zsytony

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Java]Java的堆内存和栈内存解析--举例进行内存分析相关的知识,希望对你有一定的参考价值。

[Java]Java的堆内存和栈内存解析–举例进行内存分析

明确概念

从堆和栈的功能和作用来通俗的比较,堆主要用来存放对象的,栈主要是用来执行程序的。

堆内存(Heap)

  • 通常是成员分配和释放的,C/C++是由程序员进行释放或者程序结束时回收,Java中由垃圾清理机制进行释放和回收。
  • new出来的对象和数组是放在堆内存中。堆内存是运行时的数据区,垃圾收集器会自动进行回收,但因为是运行时动态分配的内存,存取速度较慢。
  • 垃圾回收机制是通过判断堆内存中某块被分配的空间的引用数实现的,即存在一个引用计数器,任何引用计数为0的对象会被作为垃圾被收集。

栈内存(Stack)

  • 基本类型的变量和对象的引用变量在栈内存中分配.
  • 当超过变量作用域后,java会自动释放掉为该变量分配的空间。

两者联系

栈内存中的变量指向堆内存中的变量,相当于java中的“指针”

实例说明

代码

//
class BirthDate 
    private int day;
    private int month;
    private int year;

    public BirthDate(int d, int m, int y) 
        day = d; 
        month = m; 
        year = y;
    

    public void setDay(int d) 
        day = d;
    

    public void setMonth(int m) 
        month = m;
    

    public void setYear(int y) 
        year = y;
    

    public int getDay() 
        return day;
    

    public int getMonth() 
        return month;
    

    public int getYear() 
        return year;
    

    public void display() 
        System.out.println
        (day + " - " + month + " - " + year);
    



public class Test
    public static void main(String args[])
        Test test = new Test();
        int date = 9;
        BirthDate d1= new BirthDate(7,7,1970);
        BirthDate d2= new BirthDate(1,1,2000);    
        test.change1(date);
        test.change2(d1);
        test.change3(d2);
        System.out.println("date=" + date);
        d1.display();
        d2.display();
    

    public void change1(int i)
        i = 1234;
    

    public void change2(BirthDate b) 
        b = new BirthDate(22,2,2004);
    

    public void change3(BirthDate b) 
        b.setDay(22);
    

流程分析

  1. 从main开始分析
    • 在栈内存中生成了一个test变量,指向堆内存中new出来的Test对象
  2. int date = 9
    在栈内存中生成了一个变量date:9
  3. BirthDate d1= new BirthDate(7,7,1970);
    • 在栈内存中生成了一个d1变量,指向堆内存中new出来的BirthDate对象
    • new出来的BirthDate对象包含三个变量 年月日
    • 栈内存中生成三个临时变量年月日,赋值给堆内存中的BirthDate对象的三个成员变量
      至此 图如下
    • 赋值完成后,三个临时变量的生命周期结束,在栈内存中被释放。
  4. d2的生成过程如d1,不再赘述
  5. test.change1(date);
    • 调用change1函数时,会在栈内存中生成变量 i ,i=date ,值传递i=9,执行函数时,i=1234,函数执行完成后,局部变量消失,i被释放掉,内存中状态不发生变化


  6. test.change2(d1);
    • 调用change2时,在栈内存中生成b变量,传递参数时,b指向的d1所指向的对象
    • 执行函数时,与第3部相同的,b指向了在堆内存中生成了一个BirthDate对象
    • 指向完毕后,b变量消失,堆内存中只剩下一个BirthDate对象,此时该对象的引用计数为0,java的垃圾回收机制会自动将其内存回收。

      7.test.change3(d2);
    • 类似于6,临时变量b先指向了d2指向的对象,指向方法时,调用b.setDay(22),在栈内存中生成临时变量d = 22,将其赋值给堆内存中d2指向的对象的day变量。执行完成后,b和d变量消失,堆内存中对象的日期被更新

内存分配策略

程序运行时,内存分配有三种策略

  • 静态分配
  • 栈式分配
  • 堆式分配

静态内存分配

编译时确定每个数据目标的存储需求,分配固定的内存空间,故要求程序代码中不能有可变数据结构,也不能有嵌套和递归。

栈式内存分配

也称为动态内存分配,由一个类似于堆栈的运行栈实现,程序对数据去的需求在编译时不知道的,只用运行时才能知道。但是一般规定,运行时,进入一个程序模块之前,必须知道该程序模块数据去大小才能分配内存,按照先进后出的原则分配。
通俗的说就是,要求在运行时程序模块的入口处必须知道所有的存储要求。

堆式内存分配

专门负责编译时或运行时模块入口都无法确定存储需求的数据结构的内存分配,如可变长数据结构和对象实例,有大片可利用的块或者空闲块组成,可以按照任意顺序分配和释放。

参考资料:

http://www.cnblogs.com/laoyangHJ/articles/java_gc.html
http://www.java800.com/jc-59050343.html
http://www.cnblogs.com/whgw/archive/2011/09/29/2194997.html

以上是关于[Java]Java的堆内存和栈内存解析--举例进行内存分析的主要内容,如果未能解决你的问题,请参考以下文章

Java中的堆内存和栈内存

java中的堆内存和栈内存

Java堆和栈的区别和介绍,JVM的堆和栈

java中的堆和栈

Java的堆和栈

Java 中的堆和栈