菜鸟日记2--内存空间

内存空间及内存分配

  1、栈(Stack)【运行内存、内存条】

    什么是栈内存

      可以将栈比喻成一个箱子或者木桶,有一端封闭了。

      计算机内存中分配出来的一块空间,用来提供浏览器执行代码的执行环境,以及存储基本类型的值(java中的数据类型不一定存储到栈内存中,取决于基本类型在何处声明)

      例:就比如成员变量,对于成员变量来说,不论是基本数据类型还是引用类型,他们都会存储在堆内存或者方法区中

    基本类型值

      除了对象(引用数据类型)

      引用数据类型:

         主要分为三种:类、接口、数组

      类Class引用

       1、Object:一个很重要的类,Object是类层次结构的根类,每个类都使用Object作为超类,所有对象(包括类数组)都实现这个类的方法。用Object可以定义所有的类。   

Object object = new Integer(1);//来定义一个Integer类
Integer  i = (Integer)object;//来把这个Object的类强转成Integer类

       2、String:String类代表字符串,java程序中所有的字符串字面值("adb")都作为此类的实例来实现。检查单个字符、比较字符串、搜索字符串、提取子字符串、创建字符串副本、在该副本中、所有的字符都被转换成大写或小写形式。

       3、Date:表示特定的瞬间,精确到毫秒。现在Date的类一般被Calender和GregorianCalendar所有代替。

       4、void:void是一个不可实例化的占位符类,它保持一个对代表java关键字的Class对象的引用。

      接口interface引用

       1、List<E>:列表,此接口的用户可以对列表中每个元素的插入位置进行精确的控制,用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。List接口提供两种搜索指定对象的方法

       2、add():在列表中插入指定元素

       3、remove():移除列表中指定位置的元素

       4、get(int index):返回列表中指定位置的元素

    栈内存的操作

      通常的操作有入栈(压栈)、出栈(弹栈)、栈顶元素

      若要读取栈中的某个元素,就是将其之间的所有元素出栈(弹栈)才能完成。    

    栈内存特点

      优点:

        连续存储的数据结构,具有先进后出的性质

        存取速度比堆块,仅次于寄存器。

        栈数据可以共享

          例:

int a=3int b=3;
a=4;

          输出a=4,b=3,

          如果是两个对象的话,那就不一样,多个对象指向的是同一个引用,一个发生改变,另一个也会发生改变  

复制代码
//创建第一个对象
    
Student  a=new Student();

a.name="张三";
a.age=12;

//把第一个对象的地址值赋值给第二个对象

Student b=a;

b.name="李四";
b.age=22;

System.out.println(a.name+a.age);//输出“李四”,22
System.out.println(b.name+b.age);//输出“李四”,22       
复制代码

      缺点:

        栈中的数据大小与生存期必须是确定的,缺乏灵活性

    栈内存分配机制

      栈是内存中给一个线程预留的内存空间。

      由编译器自动管理分配和释放,不需要的时候自动清除的变量的存储区。

      栈内存也可以称为一级缓存,由垃圾回收器自动回收(可以延伸)

    栈内存分配方式

      动态分配:由alloca函数进行分配

      静态分配:编译器完成(局部变量的分配)

    栈内存分配效率

      栈内存分配效率相比于堆来说高。为什么呢?

      栈是机器系统提供的数据结构,计算机会在底层提供对栈的支持,会给他分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行。

    栈内存应用范围

      由于堆频繁的new/dalete会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低,同时没有系统的支持,导致堆的效率很低,加上可能引发用户态和核心态的切换,内存的申请,代价变得更加的昂贵。

      所以,栈在内存中应用非常的广泛

        1、函数的调用

        2、函数调用过程中的参数、返回地址、EBP、局部变量都采用栈的方式存放

      但是,由于栈的不灵活性

        在面对分配大量的内存空间的时候,还是用堆来完成

    栈内存扩展

      存放的都是方法中的局部变量或者函数参数等。

      方法的运行一定要在栈当中

    栈内存的主要功能

      主要是用来执行程序用的。

      例:基本类型的变量、对象的引用变量。

    局部变量:方法中的参数,或者方法{}内部的变量

    作用域:一旦超出作用域,立刻从栈内存当中消失

    总结:

      所谓的栈内存,其实就是计算机内存中分配出来的一块空间,用于提供浏览器执行代码的执行环境,以及存储基本类型值

  2、堆内存(Heap)【存储空间、硬盘】

    什么是堆内存

      可以将堆比喻成一个倒过来的树,一般用来存放关键字new出来的数据。

      经过排序的树形数据结构,每个结点(分支的地方)都有一个值,整颗树是经过排序的

      官方:java虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在java虚拟机启动时创建的。在JVM中,堆之外的内存称之为非堆内存(Non-heap memory)

      简单来说:JVM管理两种类型的内存,堆和非堆

           1、堆时java代码可及的内存,是留给开发人员用的

           2、非堆是JVM留给自己的,非堆有:

              1、方法区

              2、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)

              3、每个类结构(运行时常数值、字段和方法数据)

              4、方法和构造方法的代码

    堆的分类

      全局堆、局部堆

      全局堆就是没有分配的空间

      局部堆就是用户分配的空间

     例子

int * a = new int(0);//分配内存并初始化

       通过关键字new开辟出来了一个堆空间

       a变量存储在栈内存中,a的指针指向堆内存中的地址值  

       当不使用a的时候,要手动释放内存

delete a;

       这里,只是将a指向的内存空间释放了,但是a本身并没有撤销,该指针所占空间并未释放,该指针还是指向原来的地方。

    堆内存的分配与释放

      堆内存一般是由程序员自己分配释放,在操作系统堆进程初始化的时候进行分配,运行的过程中也可以向系统要额外的堆内存,但是记得用完要换个操作系统,要不然程序结束的时候可能由os回收,但不一定,会造成内存泄漏。

      堆内存的分配有点类似于数据结构的链表。

    堆内存特性

      必须是完全二叉树

      任一结点的值是其子树所有结点的最大值(最大堆、大顶堆)或者最小值(最小堆、小顶堆)

      根结点的值要么最大(或者最小),且根结点的两个子树也是一个堆。常用来实现优先队列,存取随意

    堆的基础实现

      1、维持完全二叉树

      2、子类数字总是大于父类数字

    扩展:无论是堆内存还是栈内存,都要防止越界现象的发生。因为,越界的结果要么使程序崩溃,要么摧毁程序的堆、栈结构,会产生想不到的结果,就算没有发生,也要小心。

     堆的数据结构

      1、堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是由链表存储在空闲的内存地址,自然堆也是不连续的内存区域。

      2、由于堆内存是类似于链表的存在,所以,其遍历也是从低向高地址遍历。

    堆内存的地址值

      堆内存的东西都有一个地址值:16进制

    堆内存里面的数据

      都有默认值

    3、堆内存与栈内存的不同

      1、管理方式不同

        栈:系统自己管理

        堆:程序员分配

      2、空间大小不同

        栈:小

        堆:大

      3、能否产生碎片不同

        栈:不产生

        堆:产生

      4、生长方式不同

        栈:向低地址扩展,连续(栈顶的地址值和栈的最大容量系统内定好了)

        堆:向高地址扩展,不连续

          

      5、分配方式不同

      6、分配效率不同

        栈:系统自动分配,速度块

        堆:程序员手动分配,速度慢

      7、存储内容不同

        栈:第一个进栈的是主函数的下一条指令的地址值,然后是函数的各个参数,在各大编译器中,参数一般是从右到左进入栈中,然后是函数中的局部变量。注意,静态变量不入栈,出栈则刚好相反

        堆:用一个字节存放堆的大小,具体由程序员安排

      8、生存周期不同

        栈生存周期短

        堆内存长,从程序开始到程序结束

      9、异常抛出不同

        栈内存满的时候:java.lang.StackOverFlowError

        堆内存满的时候:java.lang.OutOfMemoryError:java Heap Space

    总结:

      不好记,就记住

        1、引用类型总是放在堆中,看到new就是放在堆中

        2、值类型和指针总是放在它们被声明的地方

        (2解释:栈是负责保存我们的代码执行【或调用】时的路径。当我们的代码开始调用一个方法时,将放置一段编码指令【在方法中】到栈上,紧接着放置方法的参数,然后代码执行到方法中的被“压栈”至栈顶的变量位置)

    4、浅谈常量池

      常量池分类

        1、Class常量池

        2、运行时常量池

        3、全局字符串常量池

        4、基本类型包装类对象常量池

        https://cloud.tencent.com/developer/article/1450501

    以下这俩有空再写吧,菜鸟理解不太够

    5、浅谈内存溢出

    6、浅谈内存泄漏

    

 

  

  

posted @   临渊行舟  阅读(110)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示