菜鸟日记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=3; int 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、浅谈内存泄漏
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具