如果定义"垃圾"?
没有引用指向的任何对象都叫做"垃圾"
java是由GC帮助回收垃圾,开发效率高,但是执行效率低。
如何找到"垃圾"?
1.引用计数:有一个引用指向对象就在这个对象上计数加一,不能解决循环引用问题(会一直引用计数为1,没有其他引用指向他们)。
2.根可达算法:从根对象开始搜索(根对象:线程栈变量,静态变量,常量池,JNI指针(调用了C,C++本地方法叫JNI指针)(程序起来就要用的对象就是根对象))根据根对象找不到,叫做垃圾
垃圾回收算法
Mark-Sweep 标记清除
1.通过GC roots 要进行两次扫描(第一遍找出有用的,第二遍把没用的找出来清理,第一次标记第二次清除)
2.容易产生碎片(回收了之后前面不压缩不整理会产生空缺)
3.存活对象比较多的时候效率就会很高,从根找出来的存活对象多,要清除的比较少。
Copying 拷贝
1.内存一分为二,有用的拷贝到一边,另一边没用的全都清除掉
2.会发生对象的复制和移动,需要调整对象引用(因为对象被移动了)
3.只需要进行一遍扫描,然后复制对象,适用于存活少,需要回收的多
Mark-Compact 标记压缩
1.有用的全都整理到前面去,剩下的其他没用的全都清除掉
2.空间连续没有碎片,找到不可回收的移动到前面扫描两次还要移动对象(第一遍找出有用的,第二遍移动)
3.不会产生碎片,方便对象分配,内存不会减半
堆内存逻辑分区(不适合不分代的垃圾收集器)
hotSpot用的是分代算法
新生代大量死去,少量存活,采用复制算法
老年代存活率搞,回收较少,采用mc或者ms
新生代/老年代=1:2(分代模型里面默认的关系)
部分垃圾回收器使用分代模型
除Epsilon ZGC Shenandoah的GC都是使用逻辑分代模型
G1是逻辑分代,物理不分代
除此之外不仅逻辑分代,而且物理分代
一个对象的消亡过程
1.对象产生的时候会尝试栈上分配
2.栈上分配不下会尝试放到伊甸区
3.伊甸区经过一次垃圾回收之后进入s区
4.s区再经过一次垃圾回收之后进入s1区
5.然后再s和s1之间来回,什么时候年龄到了就进入old区(多次垃圾回收进入old区)
新生代回收的叫MinorGC/YGC:年轻代空间耗尽时触发
MajorGC/FullGC:老年代无法继续分配空间时触发,新生代老年代同时进行回收
什么对象会分配到栈上?
线程私有小对象:小对象,线程私有。
无逃逸:就在某一段代码使用。
支持标量替换:用普通属性代替对象。
线程本地分配TLAB
1.在栈上分配不下了就会进行线程本地分配占用eden。默认百分之1 (每个线程占用百分之1,免得线程竞争,这个线程独有,分配对象的时候先往线程独有的地方分配)
2.多线程的时候不用竞争eden就可以申请空间,提高效率
3.小对象
老年代
大对象
在打开栈上分配和线程本地分配产生对象的效率会变高,速度会快。
对象何时进入老年代
超过XX:MaxTenuringThreshold指定次数(YGC)
不指定默认如下:
1.parallel scavenge 15
2.cms 6
3.g1 15
动态年龄
1.s0->s1超过50%:s0对象拷贝到s1里面,且此时S1中对象超过百分之五十的话,就把年龄最大的放进old区
2.把年龄最大的放入Old
ps:1.8的新生代老年代对比,查询命令
java -XX:PrintFlagsFinal -version | grep NewRatio