JVM,即Java Virtual Machine(Java 虚拟机)的简称。
JVM位于操作系统之上,是一个抽象化的计算机,有自己独立的硬体架构,如寄存器、堆、栈等。JVM屏蔽了与不同操作系统平台的相关信息,使得Java程序在编译时只需要生成能在虚拟机上运行的字节码文件,就可以在多种平台上不加修改的运行。
Java语言一个非常重要的特点就是平台无关性,一个重要的原因就是Java程序编译的字节码文件在虚拟机运行时,会被解释器解释为特定操作系统的机器指令代码,这也是Java程序能够一次编译,到处运行的原因。
类加载器的作用就是用来加载Class文件。除虚拟机自带的加载器外,一般按照顺序还有根加载器(BootstrapClassLoader,负责加载lib包下的jar包和class),拓展类加载器(ExtClassLoader,负责加载lib/ext下的jar包和class)和应用程序类加载器(APPClassLoader,负责加载classpath下的类文件)。
类在进行加载时,首先会调用AppClassLoader的loadClass方法来加载这个类,这个方法会首先调用ExtClassLoader的loadClass方法,同理继续调用BootstrapClassLoader中的loadClass方法,如果BootstrapClassLoader加载到了就直接成功并返回,否则由ExtClassLoader来进行加载,成功则返回,否则由AppClassLoader进行加载。如果没有任何加载器能加载,就会抛出ClassNotFoundException。
所谓双亲委派,就是指类加载的时候会委派给Ext和Bootstrap类加载器来进行加载,如果没加载到才由自己加载。
沙箱安全(双亲委派安全性和健壮性)
package java.lang;
public class String{
//会报出在类java.lang.String中找不到main方法,因为实际加载的是Bootstrap下的String类
public static void main(String[] args){
System.out.println("1231232");
}
}
优点:
1.引用计数法
2.可达性分析法
GC Roots的对象:
垃圾回收主要针对的是JVM的堆内存,分为新生代和老年代,在1.7及之前,还有永久代,它在方法区里保存了class信息,静态变量和常量池等。JDK1.8之后取消了永久代的概念,多出了一个元空间的概念,内存上也独立了出来,跟老年代物理上不再连续,直接使用JVM内存,拓展变得更加容易实现。同时方法区也将一些数据转移了出去,比如类的静态变量,字符串常量池。
我们平常使用的JVM通常是Hotspot(都是Sun公司的,合并了JRockit)版本,此外还有Zing,J9VM等等。 永久代只是Hotspot独有的概念。
在垃圾回收中,针对新生代的垃圾回收,叫minorGC,也叫YoungGC,YGC,针对老年代的垃圾回收,叫majorGC,由于老年代垃圾回收的时候经常会伴随新生代的垃圾回收,因此也叫FullGC(全局GC),FGC。
当垃圾回收器将内存扫描后会标记出所有的垃圾对象,然后将他们回收,但是会不断的产生内存碎片,使得内存的使用率越来越低。
准备两块一模一样的内存,当其中一块空间不足时,我们可以将所有需要保留的对象拷贝到另一块内存,然后将原来的这块内存全部清空,这样就既做到了垃圾回收,又做到了碎片整理。但是对于空间的要求比较大,且利用率不高。像新生代中的两块幸存者区就是为了实现这个算法。
其实就是在清理垃圾的基础上,多了碎片整理的工作,显然这样的工作不适合高频率的执行,一般当老年代的空间不足时,会触发一次FullGC,这时就会做碎片整理的工作。
最终:
上图中B、C、H就是可以回收的对象。
OOM即Out Of Memory。内存溢出问题,包括堆内存溢出、栈内存溢出和方法区内存溢出。
OOM的解决不是一蹴而就的,一般系统在发生这种问题时,都会产生dump文件,可以使用专业工具对dump文件进行分析,找出当时异常的对象和线程(比如cpu占用特别高),接着定位到具体代码,通过分析、推理、实践和总结进行调整的。
StackOverFlow即栈溢出,每一个线程启动时,虚拟机都会为它分配一个栈,当线程调用一个方法时,就压入一个栈帧到这个线程的栈中,如果方法的嵌套太多或者互相递归调用,就会出现StackOverflowError溢出异常。
STW即Stop The World,是指在执行垃圾回收算法时将JVM内存冻结的一种状态。
在STW状态下,除了GC线程和native方法外,Java所有线程都是停止运行的,而且无法与JVM进行交互。
GC各种优化算法的重点,就是尽可能的减少STW次数,这也是JVM调优中很重要的一部分。