栈和堆
1、栈
为什么main()先执行,最后结束
栈:栈内存,主管程序的运行,生命周期和线程同步
线程结束,栈内存也就是释放,对于栈来说,不存在垃圾回收问题
一旦现场结束,栈就over!
栈:8大基本类型+对象引用+实例的方法
栈运行原理:栈帧,程序运行的方法一定是在栈顶
栈满了就是StackOverflowError
2、堆(HotSpot)
Heap,一个JVM,只有一个堆内存,堆内存大小是可以调节的
类加载器读取了类文件后,一般会把什么东西放入堆中,类、方法、常量、变量~,保存所有的引用类型的真实对象
堆内存中还细分为三个区域
- 新生区(伊甸园区)Eden Space:
- 类:一个类诞生和成长的地方,甚至死亡;
- 伊甸园区,所有的对象都是在伊甸园区new出来的
- 幸存者区,0和1,
- 养老区
- 永久区:元空间(1.8)、方法区,这个区域是常驻内存的,用来存放jdk自身携带的Class对象。Interface元数据,存储的是java运行时的一些环境或类信息~,这个区域不存在垃圾回收。关闭jvm就会释放这个区域的内存~
- 1.8之後,常量池在云空间
GC垃圾回收,主要是在伊甸园去和养老区
假设内存满了,OOM,堆内存不够,OutOfMemoryError
真哩:经过研究,99%的对象都是临时对象。
3、调优
默认情况下:分配的总内存是电脑的1/4,而初始化内存:1/16
OOM:
1、尝试扩大堆内存,看结果
2、分析内存,看哪个地方出现问题
4、GC算法
垃圾回收算法理解:https://zhuanlan.zhihu.com/p/297965515
JVM在进行GC时,并不是对这三个区域统一回收,大部分时候,回收的都是新生代~
- 伊甸园区
- 幸存区(from,to)
- 老年区
1) 引用计数法
2) 复制算法
3) 标记清除算法
对用过的对象进行标记,扫码所有的对象,未标记的对象进行清理
4)标记压缩算法
在标记清除算法基础上增加压缩内存操作,移动标记的对象到内存的一端
总结
5、分代收集算法
根据对象存活周期的不同将内存划分为几块,入JVM中的新生代,老年代,永久代,这样就可以根据各年代特点分别采用最适当的GC算法
1.1在新生代使用复制算法: 因为新生代每次垃圾收集都能发现大批的对象已死,只有少量存活,因此选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集.
1.2在老年代使用标记整理算法:因为对象存活率高,没有额外空间对它进行分配担保,就必须采用”标记-清理“或者”标记-整理“算法来进行回收,不必进行内存复制,直接腾出空闲内存