一、什么是字节码?采⽤字节码的好处是什么?
编译器(javac)将Java源⽂件(*.java)⽂件编译成为字节码⽂件(*.class),可以做到⼀次编译到处运⾏,windows上编译好的class⽂件,可以直接在linux上运⾏,通过这种⽅式做到跨平台,不过Java的跨平台有⼀个前提条件,就是不同的操作系统上安装的JDK或JRE是不⼀样的,虽然字节码是通⽤的,但是需要把字节码解释成各个操作系统的机器码是需要不同的解释器的,所以针对各个操作系统需要有各⾃的JDK或JRE。
采⽤字节码的好处,⼀⽅⾯实现了跨平台,另外⼀⽅⾯也提⾼了代码执⾏的性能,编译器在编译源代码时可以做⼀些编译期的优化,⽐如锁消除、标量替换、⽅法内联等。
二、你们项⽬如何排查JVM问题?
对于还在正常运⾏的系统:
1、可以使⽤jmap来查看JVM中各个区域的使⽤情况;
2、可以通过jstack来查看线程的运⾏情况,⽐如哪些线程阻塞、是否出现了死锁;
3、可以通过jstat命令来查看垃圾回收的情况,特别是fullgc,如果发现fullgc⽐较频繁,那么就得进⾏调优了;
4、通过各个命令的结果,或者jvisualvm等⼯具来进⾏分析;
5、⾸先,初步猜测频繁发送fullgc的原因,如果频繁发⽣fullgc但是⼜⼀直没有出现内存溢出,那么表示fullgc实际上是回收了很多对象了,所以这些对象最好能在younggc过程中就直接回收掉,避免这些对象进⼊到⽼年代,对于这种情况,就要考虑这些存活时间不⻓的对象是不是⽐较⼤,导致年轻代放不下,直接进⼊到了⽼年代,尝试加⼤年轻代的⼤⼩,如果改完之后,fullgc减少,则证明修改有效;
6、同时,还可以找到占⽤CPU最多的线程,定位到具体的⽅法,优化这个⽅法的执⾏,看是否能避免某些对象的创建,从⽽节省内存。
对于已经发⽣了OOM的系统:
1、⼀般⽣产系统中都会设置当系统发⽣了OOM时,⽣成当时的dump⽂件(-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/usr/local/base);
2、我们可以利⽤jsisualvm等⼯具来分析dump⽂件;
3、根据dump⽂件找到异常的实例对象,和异常的线程(占⽤CPU⾼),定位到具体的代码;
4、然后再进⾏详细的分析和调试。
总之,调优不是⼀蹴⽽就的,需要分析、推理、实践、总结、再分析,最终定位到具体的问题。
三、⼀个对象从加载到JVM,再到被GC清除,都经历了什么过程?
1、⾸先把字节码⽂件内容加载到⽅法区;
2、然后再根据类信息在堆区创建对象;
3、对象⾸先会分配在堆区中年轻代的Eden区,经过⼀次MinorGC后,对象如果存活,就会进⼊Suvivor区。在后续的每次MinorGC中,如果对象⼀直存活,就会在Suvivor区来回拷⻉,每移动⼀次,年龄加1;
4、当年龄超过15后,对象依然存活,对象就会进⼊⽼年代;
5、如果经过FullGC,被标记为垃圾对象,那么就会被GC线程清理掉。
四、线程池为什么是先添加列队⽽不是先创建最⼤线程?
当线程池中的核⼼线程都在忙时,如果继续往线程池中添加任务,那么任务会先放⼊队列,队列满了之后,才会新开线程。这就相当于,⼀个公司本来有10个程序员,本来这10个程序员能正常的处理各种需求,但是随着公司的发展,需求在慢慢的增加,但是⼀开始这些需求只会增加在待开发列表中,然后这10个程序员加班加点的从待开发列表中获取需求并进⾏处理,但是某⼀天待开发列表满了,公司发现现有的10个程序员是真的处理不过来了,所以就开始新招员⼯了。