JVM内存的划分有五片:
1. 寄存器
2. 本地方法区
3. 方法区
4. 栈内存
5. 堆内存
寄存器(register)
这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部,但是寄存器的数量极其有限,所以寄存器由编
译器根据需求进行分配,不能直接控制,也不能在程序中感觉到寄存器存在的任何迹象
堆和栈
堆(Heap)与栈(Stack)在不同场景下,代表不同的含义。一般情况下,有两层含义:
(1)程序内存布局场景下,堆与栈表示两种内存管理方式
(2)数据结构场景下,堆与栈表示两种常用的数据结构
程序内存中的堆和栈
栈与堆都是Java用来在Ram中存放数据的地方,Java自动管理栈和堆,程序员不能直接地设置栈或堆
1.栈的优势:存取速度比堆要快,仅次于直接位于CPU中的寄存器(堆栈指针若向下移动,则分配新的内存;若向上移
动,则释放那些内存,这是一种快速有效的分配存储方法)
缺点:存在栈中的数据大小与生存期必须是确定的,缺乏灵活性
2.堆的优势:可以动态地分配内存大小,所有用new构造出来的对象都在堆中存储,生存期也不必事先告诉编译器,比较
灵活,Java的垃圾收集器会自动收走这些不再使用的数据
缺点:由于要在运行时动态分配内存,存取速度较慢
3.常量池:存放字符串常量和基本类型常量
常量池的好处:为了避免频繁的创建和销毁对象而影响系统性能,实现了对象的共享
例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中
(1)节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间
(2)节省运行时间:比较字符串时,==比equals()快
申请响应
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出
堆:操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空
间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,对于大多数系统,会在这块内存空间
中的首地址处记录本次分配的大小,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分
重新放入空闲链表中
申请限制
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。栈顶的地址和栈的最大容量是系统预先规定
好的,如果申请的空间超过栈的剩余空间时,将提示overflow,从栈获得的空间较小
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。由于系统是用链表来存储的空闲内存地址的,自然是不连的,
链表的遍历方向由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。堆获得的空间比较灵活,也比较大
堆栈缓存方式
栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放
堆则是存放在二级缓存中,调用这些对象的速度要相对来得低一些
内存泄漏
虽然垃圾回收器的效率很高,但是单凭一个算法并不能很好的去管理内存
经常容易出现内存泄漏的地方:
1):全局变量:如果不断的去创建全局变量,不管这些变量有没有被应用,他们都是存在的,在程序的整个执行过程中,
他们都会滞留在某一个空间内,如果这些变量是嵌套多层的对象,那么就会占用和浪费更多的内存
2):事件监听器:在一个页面中,我们可能会由于一些动画效果等需求,使用到大量的监听器,监听一个事件的触发,然
后去实现一些效果,但是在用户离开这个页面的时候这些监听器并没有被移除掉,那么这个也是会造成内存的泄漏的
3):intervals 和 timeout:在使用定时器或者延时器的时候,我们经常会和必报一起使用,比如说去抖和节流使用的时
候,在我们使用闭包的时候,有时候回去定义一些变量,但是我们在处理的时候经常会只是去清除了一下 intervals 或者
timeout 并没有是清除这个闭包,这样的话,没有清除闭包,那么这些变量就也没有被清除掉,其实这还是造成大量的变
量引起的内存泄漏问题
4):DOM的清除和操作:我们在使用DOM 去进行一些操作的时候,有时候为了性能的考虑,我们会用一个变量去赋值这
个DOM,这样从另一方面,也是变量定义的一个过程,这样这个变量就一直的存在了