TLAB:默认给每一个线程开辟一块内存空间存放线程自己的对象
Class对象是存放在堆区的,不是方法区,类的元数据元数据并不是类的Class对象,Class对象是加载的最终产品,类的方法代码,变量名,方法名,访问权限,返回值等等都是在方法区的,代码信息只是在方法区;
对齐填充:方便计算机寻址存取方便,是计算机寻址最优的一种方式
压缩前:一开始String和Object都是占用的是8个字节,这些对象地址放到堆里面,开启某一个参数以后可以让对应的对象的内存地址压缩到四个字节
压缩以后:
init方法:成员变量真正进行赋值,之前是0,并且调用对象的构造方法
标量替换:对于一个对象来说,如果采取栈上分配,不会new一个对象在栈上面,而是将它的成员变量属性剥离开存放分配在栈上,分开存,这几个字段会进行标识是属于哪一个对象的,前提是开启了逃逸分析;
1)大对象直接放到老年代:可以设置参数
如果你知道系统创建的对象比较大,况且这些对象不会被垃圾收集的,Serial+ParNew有效,JVM会直接判断对象大小,就是为了降低大对象分配内存的时候复制对象而降低效率
2)达到分代年龄存放到老年代:可以设置参数
大概知道很多new对象生命周期不是特别长,可能要用一段时间,没有执行时间特别长的方法,或者其他的情况,程序员大概可以估算到一个方法中有一个大对象,但是方法结束非常快,可能一两次GC就被干掉,分代年龄尽量设置的少一些,可以尽快节省新生代的空间
3)对象动态年龄判断机制:
对于订单系统来说,每秒钟有60M对象会向伊甸园区里面存放,1S以后变成垃圾对象
当前放对象的Survior区域里面(其中一块区域,放对象的那一块S区),一批对象的总大小大于这块Survior区域的50%(-XX:TargetSurivorRatio可以指定),那么此时大于等于这一批年龄对象的最大值的对象,就可以直接存放到老年代了,假设现在幸存者区里面有一批对象,年龄1+年龄2+年龄N的多个年龄对象超过了Surivor区域的50%,此时就会把年龄N以上的对象全部放在老年代,这个规则是希望那些可能长期存活的对象尽早地进入到老年代,对象年龄判断机制其实是在minor GC以后触发的;
1)大概13秒或者14s来说伊甸园区就会被放满,会触发minorGC,会把伊甸区的对象全部进行垃圾回收,前面13s的对象做minor GC的时候都是可以回收掉的,但是伊甸区第14s产生的对象会触发minorGC,因为此时订单正在执行过程中,14s产生的对象都被GCROOTS引用着,所以此时这60M对象会被存放到S0区域,但是前面13s产生的对象会被伊甸园区直接被干掉,因为之前伊甸区的方法已经结束了,生成订单非常快;
2)但是最终情况是:这60M对象会被分配到老年代,每隔14s有60M对象放到老年代,等到一段时间5 6min就会发生FullGC,但是其实这些对象其实早就变成垃圾了,因为正常的订单对象早就变成垃圾了1S终究欸有引用指向它,这种情况不太好;
3)这个时候朝生夕死的对象太多,于是就适当提高年轻代的空间大小,频繁导致FullGC的原因就是动态年龄判断机制,使用两种机制来优化,一种是调整surivor区域,一种是把年轻代调整的大一些,几乎不发生FullGC;
适当提升新生代的比例之后:第24s以后对象的空间已经满了,那么此时这个25S产生的60M对象会直接存放到幸存区,此时触发minorGC会进行回收伊甸园区和幸存者区,增大新生代;
4)老年代动态分配担保机制:当JVM在做minor GC之前,如果大概率先做FullGC,再来做minorGC,那么这个minorGC非常快时间非常短,如果你不做这个判断,做完minorGC之后再来做fullGC,那minor GC耗费的时间比较多,FullGC耗费的时间也会很多;
1)JVM会进行判断老年代剩余有效的空间如果小于年轻代所有对象(包含垃圾对象)的空间,如果老年代不能容纳下来新生代的所有对象,假设说如果新生代的所有的对象直接挪到老年代了,放不了就会直接出发fullGC,然后JVM会判断一个参数;
2)如果老年代能容纳下来新生代的所有对象(大于等于),那么直接进行minor GC
3)此时如果你设置了这个参数,那么直接会进行判断老年代可用空间是否小于历史上每一次minor GC之后进入到老年代的对象的平均大小,假设每一次minor GC,第一次挪了50M,第二次挪了60M,第三次挪了100M,那么JVM会计算这三次挪到老年代的平均内存大小,(50+50+100)/3,如果大于,肯定会做FUllGC,再做minorGC;
4)如果小于那么直接做minor Gc;
5)如果没有设置参数,直接做fullGC;
如果调整完新生代的大小之后将晋升到老年代的空间调服务器托管网整成5了,因为这种情况是每25S触发一次minorGC,触发一次GC,分代年龄+1,分代年龄达到5,说明已经过去了好几分钟了,所以说这些已经达到5的对象早就已经变成垃圾了,要么赶紧被清理掉,如果分代年龄达到5,说明这样的对象肯定不是简单的GC对象肯定不容易被收集,这样的对象肯定是系统中的缓存对象,Spring Bean对象,线程池的引用对象,对于这些对象可以让她尽量的早点老年代,不要再年轻代里面占用过多的那些朝生夕死的对象的空间了,订单对象库存对象,优惠劵对象的空间了,让那些年轻代的对象能够在年轻代就被干掉;
使用G1垃圾回收器,内部算法耗费的性能比CMS要高
CMS触发FullGC比例可能会导致部分空间不可用,如果FullGC发生频率很低,这时就可以启动serial Old来进行清理,设置参数是0,每一次FullGC,serial Old会清理一次内存碎片,但是如果出现秒杀活动,就尽量减少内存碎片的整理,因为不敢让用户线程停止,这时候就可以配置5次FullGC一次清理,如果长时间不做内存清理,那么老年代的连续可用内存空间会越来越少;
fullGC回收类元信息和堆空间
没有类原信息,对象的对象头已经没有指针指向这个类原信息,但是这三种类加载器不会被回收,所以服务器托管网加载的类不会被回收;
所有的classLoader都会记录着所有它加载过的类信息
Class对象是可以创建出对象
内存泄漏篇:
常见工具的使用:
1)jps
2)jstat
jstat -class +进程的端口号,类的加载数,占据的总体字节数,卸载数,占用的总体时间
jstat -class +进程的端口号+每隔多少毫秒打印一次,下面的这种情况默认是1000ms打印一次直至程序终止
jstat监视虚拟空间的占用和垃圾回收的行为
jstart -class -t +进程的ID
jstat -gc +进程的PID
jstat -gccause+ID,进行查看gc的原因
能够计算出这两段区间内gc的执行时间,后面GC的间隔时间/程序间隔运行时间,可以看出垃圾回收时间占总共程序运行时间的比例
隔一段时间找一个最小值,隔一段时间找一个最小值
3)
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net