元空间
元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。JDK1.7及之前用永久代,JDK1.8开始用元空间。
字符串常量(池):JDK 1.7 和 1.8 将字符串常量由永久代转移到堆中。
字面量(interned strings):转移到了java heap;
类的静态变量(class statics):转移到了java heap。
运行时常量池(class文件元信息描述,编译后的代码数据,引用类型数据,类文件常量池):存在于本地内存的元空间中。
(所谓的运行时常量池其实就是将编译后的类信息放入运行时的一个区域中,用来动态获取类信息。运行时常量池是在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中,也就是说,每个class都有一个运行时常量池,类在解析之后,将符号引用替换成直接引用,与全局常量池中的引用值保持一致。)
方法区元空间实现之jdk7和8字符串常量池、运行时常量池、静态变量到底在哪?_一个长不胖的程序YUAN的博客-优快云博客
JVM调优:目标是减少full GC,减少STW
JVM诊断:排除各种问题
1)栈(线程)诊断
2)堆诊断
调优:
年轻代太小(老年代过大),会导致对象未达到年龄15就进入老年代,增加full GC的次数,且老年代过大每次full GC的stw过长。
年轻代过大,老年代过小,导致老年代频繁full gc。
注:年轻对象进入老年代的条件:(动态对象年龄判定:为了能更好地适应不同程度的内存状况,虚拟机并不是永远地要求对象的年龄必须达到了MaxTenuringThreshold才能晋升到⽼年代,如果在Survivor空间中相同年龄的所有对象⼤⼩的总和⼤于Survivor空间的⼀半,年龄⼤于或等于年龄的对象就可以直接进⼊⽼年代,⽆须等到MaxTenuringThreshold中要求的年龄。)
-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆 栈大小为1M,以前每个线程堆栈大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一 个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
工作中一般设置256K。
线程栈的大小是个双刃剑,如果设置过小,可能会出现栈溢出,特别是在该线程内有递归、大的循环时出现溢出的可能性更大,如果该值设置过大,就有影响到创建栈的数量,如果是多线程的应用,就会出现内存溢出的错误.
CMS的问题
1,因为他是标记清理,所以会内存碎片化,导致当有大对象进来时,没有足够的内存而进行fullGC。
2,CMS的垃圾清理和引用线程是并行进行的,如果在并行清理的过程中老年代的空间不足以容纳应用产生的垃圾(也就是老年代正在清理,从年轻代晋升了新的对象,或者直接分配大对象年轻代放不下导致直接在老年代生成,这时候老年代也放不下),则会抛出“concurrent mode failure”。concurrent mode failure会导致老年代的垃圾收集器从CMS退化为Serial Old,所有应用线程被暂停,停顿时间变长。
concurrent mode failure_快乐的小J的博客-优快云博客
G1
G1的目标是减少停顿时间,目标是用在多核,大内存的机器上,他是软实时的,“软实时”则是指,用户可以指定垃圾回收时间的限时,G1会努力在这个时限内完成垃圾回收,但是G1并不保证每次都能在这个时限内完成垃圾回收。它在大多数情况下可以实现指定的GC暂停时间,默认是200ms(-XX:MaxGCPauseMillis=200)意思是要求 G1,在任意 1 秒的时间内,停顿时间不得超过 200ms,G1开创的基于Region的堆内存布局是它能够实现这个目标的关键。