Jvm内存分配机制:
内存分配的三种策略
1:静态存储区(方法区)
{
1.内存在程序编译时就已经分配好
2.内存在整个程序运行期间都一直存在
3.主要存放静态数据,全局static数据和常量
}
2:栈区
{
~函数(方法)中定义:{
1.基本类型的变量
2.对象的引用变量
}
~执行函数(方法)时,方法内的局部变量的存储单元都是在栈内存创建的,并且当方法执行结束后,这些存储单元会自动被释放
(由系统自动管理,无需程序员手动释放)
~栈内存分配运算内置于处理器的指令集中,效率很高
~连续的内存区域,内容容量有限,大小由系统决定
}
3:堆区
{
~动态分配内存(不连续的内存区域)
~程序在运行时通过new来申请任意大小的内存(对象,数组)
~需要程序员手动释放
~依赖于垃圾回收机制
}
总结:
堆与栈的区别{
~管理方式:栈是由系统自动管理,无需程序员手动释放; 堆是由程序员手动释放,但可能会造成内存泄漏
~申请大小:栈的内存是系统固定好的常数,是一块连续的内存区域,一旦申请空间超过栈空间,就会造成栈溢出;
堆大小受限与计算机系统中有效的虚拟内存,堆的空间比较灵活并且是一块不连续的内存区域(原因由于系统是利用链表来存储空闲内存地址)
~碎片问题:栈内存中遵循后进先出的原则,进出一一对应,不存在碎片问题,运行效率高且稳定;
堆内存中如果频繁的new/delete会生成大量的内存碎片,降低程序的效率
~分配方式:栈由静态分配和动态分配两种分配方式,静态分配内存如局部变量的分配,由编译器完成,动态分配和堆的不同,它是由编译器来释放;堆是动态分配内存,没有静态分配方式;
~分配效率:栈是计算机的数据结构,这就决定了栈的分配效率比堆的高
}
结论:局部变量的基本数据类型和引用都存储与栈中,引用的对象实体存储于堆中,因为它们是属于方法中的变量,生命周期随方法而结束
成员变量全部存储于堆中(包括基本的数据类型,引用和引用的对象实体),因为它们属于类,类是被new出来使用
4.垃圾回收机制:
1:从程序的主要运行的对象开始来检查引用链
2:遍历一遍获取当前内存中无法回收的引用实体对象和它们所对应的引用链
3:组合生成无法回收的对象集合
4:其他孤立的对象集就作为垃圾进行回收
内存泄漏和内存溢出:
内存泄漏:指程序在申请内存后,使用完成无法释放申请的内存空间
内存溢出:指程序在申请内存时,申请的内存大小超出了系统分配的最大内存空间,没有足够的空间可使用
内存溢出原因:
{
1、java.lang.OutofMemoryError:Java heap space(堆溢出 {
程序中出现了死循环
程序占用内存太多,超过了JVM堆设置的最大值
},确保代码正确的前提下,修改jvm配置)
2、java.lang.OutofMemoryError:PermGen space (常量池的膨胀)
3、java.lang.OutofMemoryError:unable to create new native thread(内存本身不够用,或是heap设置过大,导致无法为线程分配内存)
4、java.lang.OutofMemoryError:GC overhead limit exceeded(高频GC)
}
内存泄漏:
{
1.错误使用单例造成的内存泄漏
2.错误使用静态变量
3.Handler错误使用导致的内存泄漏
4.线程造成的内存泄漏
5.资源为关闭导致的内存泄漏
...
}->1:应用卡顿 2:OOM 3:应用崩溃