JVM垃圾回收机制
引用计数法:Java中,引用和对象是有关联的,如果要操作对象则需要用引用进行,因此,很显然一个简单的办法就是通过引用计数来判断一个对象是否可以回收,简单来说,给对象加引用的计数器,当有地方应用的时候,这个计数器就加1,当有一个引用失效的时候这个计数器就减1,当这个计数器为零的时候意味着这个对象不可能再被使用,所以这个对象就是可回收对象。
枚举根节点做可达性分析(根搜索路径):该算法的出现是为了解决引用计数法出现的循环引用的问题而诞生,基本的思路是通过一系列名为""GC Roots" 的对象作为起始点,从这个被称为GC Roots的对象开始向下搜索,如果一个对象到GC Roots没有任何应用链相连的时,则说明此对象不可用,属于垃圾对象。也急给定一个集合的引用作为根出发,通过引用关系遍历对象图,能被遍历到的(可达性)对象就被判断为存活。
GC Roots的对象:
- 虚拟机栈(栈帧中的局部变量区,也叫做局部变量表)中引用的对象
- 方法区中的类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI(Native方法)引用的对象
解释:方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
说明:main方法进行m1()方法的调用,方法的调用意味着,方法进入的栈,然后m1中又存在着 t1 对象的引用,那么就验证了第1条
t2 是属于类静态属性。由于static 修饰的会进入方法区中,那么就意味着,GCRootDemo有了方法区的类属性引用,也就是验证了第2条
Static final 修饰的就是常量,同时t3 还是对象引用,那么就验证了第3条
JVM调优和参数配置
JVM 的参数类型
标准参数:-version、-help、java -showversion
X参数:-Xint(解析执行)、-Xcomp(第一次使用就编译成本地代码)、-Xmixed(混合模式)
XX参数 :
Boolean类型:
公式:-XX:+或者-某个属性值 (+代表开启、-代表关闭)
KV设值类型:
公式:-XX:属性key=属性值value
JVM常见参数:
**-Xms:**初始大小内存,默认为物理内存的1/64(等价于 -XX:InitialHeapSize)
**-Xmx:**最大分配内存,默认为物理内存1/4(等价于 -XX:MaxHeapSize)
**-Xss:**设置单个线程栈的大小,一般默认为512k~1024k(等价于 -XX:ThreadStackSize)
**-Xmn:**设置年轻代大小
**-XX:MetaspaceSize:**设置元空间大小(元空间的本质和永久代类型,都是对JVM规范中方法区的实现,不过元空间与永久代的区别在于:元空间并不在虚拟机中,而是使用本地内存)
典型的配置:
-Xms 128m -Xmx4096m -Xss 1024K -Xx:MetaspaceSize=512m -XX:+PrintCommandLineFlags -XX: +PrintGCDetails -XX:+UseSerialGC
-Xms128m : 初始堆内存大小
-Xmx4096m: 初始最大堆内存大小
-Xss1024k: 初始化栈内存大小
-XX:MetaspaceSize=512m 初始化元空间大小
-XX:+PrintCommandLineFlags 打印初始的配置参数
-XX:+PrintGCDetails 打印GC回收的细节
-XX:+UserSerialGC 串行垃圾回收器
-XX:+UseParallelGC 并行垃圾回收器
**-XX:+PrintGCDetails:**打印GC回收的细节
GC 过程图解
fullGC 过程图解
**-XX:SurvivorRatio:**设置新生代中eden和S0/S1空间的比例( 默认配置-XX:SurvivorRatio = 8 等价于 Eden:S0:S1 = 8:1:1)
**-XX:NewRatio:**设置年轻代与老年代在堆结构的占比(默认配置 -XX:NewRatio=2 等价于新生代占1,老年代2,年轻代占整个堆的1/3)
**-XX:MaxTenuringThreshold:**设置垃圾最大的年龄(从新生区到养老区的回收次数)
设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过幸存者区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论
强引用 软引用 弱引用 虚引用的理解
**强引用:**当内存不足,JVM开始垃圾回收,对于强引用的对象,就算是出现了OOM也不会对该对象进行回收,死都不收。强引用是我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表明对象还"活着",垃圾收集器不会碰这种对象。在Java中最常见的就是强引用,把一 个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到JVM也不会回收。因此强引用是造成Java内存泄漏的主要原因之一。
**软引用:**软引用是一种相对强引用弱化了一些的引用,需要用java.lang.ref.SoftReference类来实现,可以让对象豁免一些垃圾收集。当系统内存充足的情况下不会被回收,如果系统内存不够将会被收回
弱引用: 弱引用需要用java lang .ref.WeakReference类来实现,它比软引用的生存期更短,对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管JVM的内存空间是否足够,都会回收该对象占用的内存。
**虚引用:**虚引用需要java.lang.rlef.PhantomReference类来实现。顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一一样,在任何时候都可能被垃圾回收器回收,它不能单独使用也不能通过它访问对象,虚引用必须和引用队列(ReferenceQueue)联合使用。