Java基础-堆内存与栈内存

java把内存划分为两种:栈内存和堆内存,堆和栈都是java用来在Ram中存放数据的地方。
一、简介:
应用程序所有的部分都是使用堆内存,然后栈内存通过一个线程运行起来。
java中进行函数调用中传递参数时,遵循的是值传递的原则,
故,基本类型传递的是该数据值本身(eg:a=1,b=a,当b=1+2时,只是b=3,a仍为1)
引用类型传递是对象的引用,即传递的是链表地址(eg:objectA=西红柿,B=objectA,只是将A的内存地址给了B)
1、栈内存
在函数中定义的一些基本类型变量和对象的引用变量,都在函数的栈内存中分配。
2.堆内存
(1)堆允许程序在运行时动态的申请某一大小的内存空间。堆内存实际上是满足堆内存性质的优先队列的一种数据结构
(2)堆内存动态申请内存空间
首先知道操作系统有一个记录空闲内存地址的链表;
其次:当系统收到程序申请时,遍历链表,寻找第一个空间大于申请空间的堆结点
再次:将寻找到的堆结点从空闲节点链表中删除,并将结点的空间分配给程序。
ps:为后期方便空间释放,在分配的空间首地址处记录本次分配的大小。
ps:当寻找到的空间>申请的空间,系统自动将多余的空间重新放入空间链表中。

二、堆内存和栈内存的对比

栈内存 堆内存
存放的内容 临时变量、局部变量(基本类型的变量、对象的引用)、方法的调用 存放所有new出来的对象(即实例变量)和数组,分配方式类似于链表
进出原则 先入后出(类似水桶) 向高地址扩展的数据结构,是不连续的内存空间,链表的遍历方向是由低地址向高地址
举例说明 例如main函数中调用test0函数,释放时先释放test0,再释放main ----
回收机制 当超过变量的作用域后,自动释放栈内存空间 垃圾收集器自动收走不再使用的数据
使用范围 栈内存不能被其他线程访问 堆内存中的队形是全局可以被访问的
内存溢出 当栈内存满时,抛出java.lang.StackOverFlowError异常 当堆内存满时,抛出java.lang.OutOfMemoryError:JavaHeapSpace错误
优缺点 栈内存小 堆内存获取空间比较灵活,比较大 ()
生命周期短 堆内存从程序运行开始到运行结束
存取速度快 存取速度慢 (容易产生内存碎片,但是用起来方便)
栈数据可以共享,but存在栈中的数据大小和生存期必须时确定的,缺乏灵活性

三、内存分析实例
(1)代码实现
本实例是定义了一个三维空间的点的类,并实现了修改坐标和求点到原点间的距离。
写该例子的思路:
1).分析出属性有:点,三个坐标(x,y,z)
方法:点的初始化(构造方法),坐标的修改(set),坐标值的获取(get),求距离的平方和
2)实现,具体代码如下

package OOP;

 class Point {
    
    
    private double  coordinateX ;
    private double  coordinateY ;
    private double  coordinateZ ;

    Point(double x,double y,double z){
    
    
      coordinateX = x;
      coordinateY = y;
      coordinateZ = z;
    }

    public void setCoordinateX(double coordinateX) {
    
    
        this.coordinateX = coordinateX;
    }

    public double getCoordinateX() {
    
    
        return coordinateX;
    }

    public void setCoordinateY(double coordinateY) {
    
    
        this.coordinateY = coordinateY;
    }

    public double getCoordinateY() {
    
    
        return coordinateY;
    }

    public void setCoordinateZ(double coordinateZ) {
    
    
        this.coordinateZ = coordinateZ;
    }

    public double getCoordinateZ() {
    
    
        return coordinateZ;
    }

    //计算点到原点的距离的平方
    public double  distanceSquare(){
    
    
        double disSquare = coordinateX*coordinateX +coordinateY*coordinateY +coordinateZ*coordinateZ;
        return disSquare;

    }
}
public class TestPoint{
    
    
    public  static void main(String args[]){
    
    
        //生成特定坐标的点对象
        Point p1 = new Point(1,2,3);
        System.out.println("生成的点是"+"("+p1.getCoordinateX() + ","+p1.getCoordinateY()+ ","+p1.getCoordinateZ() +")");

        //设置坐标
        p1.setCoordinateX(6);
        System.out.println("p1的x轴应该是6    "+p1.getCoordinateX());

        //计算点到原点的平方
        double dis1 = p1.distanceSquare();
        System.out.println(dis1);

    }

2、内存分析
(1)第一步
在这里插入图片描述
定义p1引用对象,在栈内存分配一空间1b6d3586,并在栈内存中申请一块空间;
执行new point(1,2,3):在栈内存分配x,y,z,分别为1,2,3;
coordinateX=x的值1、coordinateY=y的值2、coordinateZ=z的值3、
在这里插入图片描述

构造点完毕,x,y,z栈内存释放
在这里插入图片描述
(2)第二步调用getCoordinateX()
p1.getCoordinateX(),读取值,内存不变
(3)第三步:调用setCoordinateX(6)
1)传入参数6,首先在栈内存中增加一个空间,存放传入的参数6
在这里插入图片描述

2)执行下面的方法:
public void setCoordinateX(double coordinateX) {
this.coordinateX = coordinateX;
}
t将p1的coordinateX改写为新传入的6(这里体现了java调用中遵循值传递的原则)
此时内存为:

在这里插入图片描述
3)方法执行完毕,栈内存中释放6的存储空间
在这里插入图片描述
4、第四步,读取坐标,内存不变
5.第五步、计算距离
double dis1 = p1.distanceSquare();
栈内存中增加dis1,将计算结果存在在dis1上。
在这里插入图片描述
6.第六步:程序执行完,释放所有的内存
当System.out.println(dis1);最后一句执行完后,栈内存将释放dis1,p1;
堆收集器将不用的堆内存的数据进行垃圾回收处理。

至此,内存又恢复如初,空空如也。。。哈哈
有哪里写的不对的地方,还请指教。

猜你喜欢

转载自blog.csdn.net/qq_44801116/article/details/114190628