jvm总结

jvm总结,第1张

jvm总结

文章目录

1.JDK8和JDK7区别2.如何判断一个对象可以被回收3.哪些对象可以作为GC Roots4.JVM 三种类型参数

4.1 标配参数4.2 X参数4.3 XX参数 5.JVM XX参数

5.1 布尔类型5.2 KV键值类型 6. JVM Xms/Xmx参数7.JVM 查看参数

7.1 查看某个参数7.2 查看所有参数7.3 查看修改后的参数7.4 查看常见参数 8. JVM 常用参数

8.1 -Xmx/-Xms8.2 -Xss8.3 -Xmn8.4 -XX:metaspaceSize8.5 -XX:+PrintGCDetails8.6 -XX:SurvivorRatio8.7 -XX:NewRatio8.8 -XX:MaxTenuringThreshold 9. 四大引用

9.1 强引用9.2 软引用9.3 弱引用9.4 WeakHashMap9.5 虚引用9.7 引用队列 10. 内存溢出OutOfMemoryError

10.1 StackOverflowError10.2 OOM—Java head space10.3 OOM—GC overhead limit exceeded10.4 OOM—GC Direct buffer memory10.5 OOM—unable to create new native thread10.6 OOM—metaspace 11. 四大垃圾收集算法

11. 标记整理11.2 标记清除11.3 复制算法11.4 分代收集算法 12. 四种垃圾收集器

12.1 串行收集器Serial12.2 并行收集器Parrallel12.3 并发收集器CMS12.4 G1收集器 13. 默认垃圾收集器

13.1 默认收集器有哪些13.2 查看默认垃圾修改器 14. 七大垃圾收集器

14.1 体系结构14.2 Serial收集器14.3 ParNew收集器14.3 Parallel Scavenge收集器14.4 SerialOld收集器14.5 ParallelOld收集器14.6 CMS收集器14.7 G1收集器14.8 G1相对CMS优势 15. JVM和SpringBoot16. Linux相关指令

16.1 top16.2 vmstat16.3 mpstat16.4 pidstat16.5 free16.6 df16.7 iostat16.8 ifstat 17. CPU占用过高原因定位18. JVM性能调优和监控工具

1.JDK8和JDK7区别

Java8 JVM内存结构基本结构与之前类似,只是Java8取消了之前的“永久代”,取而代之的是“元空间”——metaspace,两者本质是一样的。“永久代”使用的是JVM的堆内存,而“元空间”是直接使用的本机物理内存。

2.如何判断一个对象可以被回收

引用计数算法:维护一个计数器,如果有对该对象的引用,计数器+1,反之-1。无法解决循环引用的问题。

可达性分析算法:从一组名为“GC Roots”的根节点对象出发,向下遍历。那些没有被遍历到、与GC Roots形成通路的对象,会被标记为“回收”。

3.哪些对象可以作为GC Roots
    虚拟机栈(栈帧中的局部变量)中引用的对象本地方法栈(native)中引用的对象方法区中常量引用的对象方法区中类静态属性引用的对象
4.JVM 三种类型参数 4.1 标配参数

比如-version、-help、-showversion等,几乎不会改变。

4.2 X参数

用得不多,比如-Xint,解释执行模式;-Xcomp,编译模式;-Xmixed,开启混合模式(默认)。

4.3 XX参数

重要,用于JVM调优

5.JVM XX参数 5.1 布尔类型

公式:-XX:+某个属性、-XX:-某个属性,开启或关闭某个功能。比如-XX:+PrintGCDetails,开启GC详细信息。

5.2 KV键值类型

公式:-XX:属性key=值value。比如-XX:metaspace=128m、-XX:MaxTenuringThreshold=15。

6. JVM Xms/Xmx参数

-Xms和-Xmx十分常见,用于设置初始堆大小和最大堆大小。第一眼看上去,既不像X参数,也不像XX参数。实际上-Xms等价于-XX:InitialHeapSize,-Xmx等价于-XX:MaxHeapSize。所以-Xms和-Xmx属于XX参数。

7.JVM 查看参数 7.1 查看某个参数

使用jps -l配合jinfo -flag JVM参数 pid。先用jps -l查看java进程,选择某个进程号。

17888 org.jetbrains.jps.cmdline.Launcher 5360 
org.jetbrains.idea.maven.server.RemoteMavenServer 18052 demo3.demo3

jinfo -flag PrintGCDetails 18052可以查看18052 Java进程的PrintGCDetails参数信息。

-XX:-PrintGCDetails

7.2 查看所有参数

使用jps -l配合jinfo -flags pid可以查看所有参数。(java8在macOS报错,需升级版本)

也可以使用java -XX:+PrintFlagsInitial

7.3 查看修改后的参数

使用java -XX:+PrintFlagsFinal可以查看修改后的参数,与上面类似。只是修改过后是:=而不是=。

java -XX:+PrintFlagsFinal -XX:metaspaceSize=20M 查看和修改

7.4 查看常见参数

如果不想查看所有参数,可以用-XX:+PrintCommandLineFlags查看常用参数。

-XX:InitialHeapSize=132375936 -XX:MaxHeapSize=2118014976 -XX:+PrintCommandLineFlags 
-XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
-XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
8. JVM 常用参数 8.1 -Xmx/-Xms

最大和初始堆大小,最大默认为物理内存的1/4,初始默认为物理内存的1/64。

Xms (InitialHeapSize) 初始堆大小,初始默认为物理内存的1/64

Xmx (MaxHeapSize) 最大初始堆大小,最大默认为物理内存的1/4

8.2 -Xss

等价于-XX:ThreadStackSize。用于设置单个栈的大小,系统默认值是0,不代表栈大小为0。而是根据 *** 作系统的不同,有不同的值。比如64位的Linux系统是1024K,而Windows系统依赖于虚拟内存。

-Xss10m //配置

8.3 -Xmn

新生代大小,一般不调。

8.4 -XX:metaspaceSize

设置元空间大小,元空间的本质和永久代类似,都是JVM规范中方法区的实现.

元空间和永久代最大区别:元空间不在虚拟内存,直接使用本地内存,默认情况下,元空间只受到本地内存大小的限制

-XX:metaspaceSize=1024m

8.5 -XX:+PrintGCDetails

输出GC收集信息,包含GC和Full GC信息

-Xms10m -Xmx10m -XX:+PrintGCDetails

GC日志

fullGC日志

[GC (Allocation Failure) [PSYoungGen: 1782K->496K(2560K)] 1782K->573K(9728K), 0.0017368 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 496K->512K(2560K)] 573K->589K(9728K), 0.0016157 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 512K->0K(2560K)] [ParOldGen: 77K->475K(7168K)] 
589K->475K(9728K), [metaspace: 3137K->3137K(1056768K)], 0.0058396 secs] [Times: user=0.02 sys=0.00,
 real=0.01 secs]
8.6 -XX:SurvivorRatio

新生代中,Eden区和两个Survivor区的比例,默认是8:1:1。通过-XX:SurvivorRatio=4改成4:1:1

-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+UseSerialGC
-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:SurvivorRatio=2

8.7 -XX:NewRatio

老生代和新年代的比列,默认是2,即老年代占2,新生代占1。如果改成-XX:NewRatio=4,则老年代占4,新生代占1。

-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:NewRatio=2 //默认配置,不写就是2

-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:NewRatio=4

8.8 -XX:MaxTenuringThreshold

新生代设置进入老年代的时间,默认是新生代逃过15次GC后,进入老年代。如果改成0,那么对象不会在新生代分配,直接进入老年代。

9. 四大引用

以下Demo都需要设置-Xmx和-Xms,不然系统默认很大,很难演示。

9.1 强引用

使用new方法创造出来的对象,默认都是强引用。GC的时候,就算内存不够,抛出OutOfMemoryError也不会回收对象,死了也不回收。详见

package com.bcl.jvm;


public class StrongReferenceDemo {
    public static void main(String[] args) {
        Object ob1 = new Object();  //这样默认定义就是强引用
        Object ob2 = ob1;           //引用赋值 是强引用
        ob1 = null;
        System.gc();
        System.out.println(ob2);
        System.out.println(ob1);
    }
}
9.2 软引用

需要用Object.Reference.SoftReference来显示创建。如果内存够,GC的时候不回收。内存不够,则回收。常用于内存敏感的应用,比如高速缓存。详见

package com.bcl.jvm;

import java.lang.ref.SoftReference;


public class SoftwareReferenceDemo {
    public static void main(String[] args) {
//        memory_enough();
        memory_not_enough();
    }

    
    public static void memory_not_enough() {
        Object ob1 = new Object();
        SoftReference softReference = new SoftReference(ob1);
        System.out.println(ob1);
        System.out.println(softReference.get());
        ob1 = null;
        try {
            byte[] bArray = new byte[30 * 1024 * 1024];
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            System.out.println(ob1);
            System.out.println(softReference.get());
        }
    }

    
    public static void memory_enough() {
        Object ob1 = new Object();
        SoftReference softReference = new SoftReference(ob1);
        System.out.println(ob1);
        System.out.println(softReference.get());
        ob1 = null;
        System.gc();
        System.out.println(ob1);
        System.out.println(softReference.get());
    }
}
 
9.3 弱引用 

需要用Object.Reference.WeakReference来显示创建。无论内存够不够,GC的时候都回收,也可以用在高速缓存上。详见

package com.bcl.jvm;

import java.lang.ref.WeakReference;


public class WeakReferenceDemo {
    public static void main(String[] args) {
        Object obj1 = new Object();
        WeakReference weakReference = new WeakReference<>(obj1);
        System.out.println(obj1);
        System.out.println(weakReference.get());

        obj1 = null;
        System.gc();
        System.out.println(obj1);
        System.out.println(weakReference.get());
    }
}
 
9.4 WeakHashMap 

传统的HashMap就算key==null了,也不会回收键值对。但是如果是WeakHashMap,一旦内存不够用时,且key==null时,会回收这个键值对。详见

package com.bcl.jvm;

import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;

public class WeakHashMapDemo {
    public static void main(String[] args) {
        myHashMap();
        System.out.println("=====================");
        weakHashMap();
    }

    public static void weakHashMap() {
        Map map = new WeakHashMap<>();
        Integer integer = new Integer(2);
        String value = "hashMap";
        map.put(integer, value);
        System.out.println(map);
        integer = null;
        System.gc();
        System.out.println(map);
        System.out.println("weakHashMap size = " + map.size());
    }

    public static void myHashMap() {
        Map map = new HashMap<>();
        Integer integer = new Integer(1);
        String value = "hashMap";
        map.put(integer, value);
        System.out.println(map);
        integer = null;
        System.gc();
        System.out.println(map);
        System.out.println("map size = " + map.size());
    }
}
9.5 虚引用

软应用和弱引用可以通过get()方法获得对象,但是虚引用不行。虚引形同虚设,在任何时候都可能被GC,不能单独使用,必须配合引用队列(ReferenceQueue)来使用。设置虚引用的唯一目的,就是在这个对象被回收时,收到一个通知以便进行后续 *** 作,有点像Spring的后置通知。详见

package com.bcl.jvm;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;


public class PhantomReferenceDemo {
    public static void main(String[] args) throws InterruptedException {
        Object o = new Object();
        ReferenceQueue referenceQueue = new ReferenceQueue<>();
        PhantomReference phantomReference = new PhantomReference<>(o, referenceQueue);
        System.out.println(o);
        System.out.println(referenceQueue.poll());
        System.out.println(phantomReference.get());

        o = null;
        System.gc();
        Thread.sleep(500);
        System.out.println("==================");
        System.out.println(o);
        System.out.println(referenceQueue.poll());
        System.out.println(phantomReference.get());
    }
}
 
9.7 引用队列 

弱引用、虚引用被回收后,会被放到引用队列里面,通过poll方法可以得到。关于引用队列和弱、虚引用的配合使用,见

package com.bcl.jvm;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

public class ReferenceQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        Object o = new Object();
        ReferenceQueue referenceQueue = new ReferenceQueue<>();
        WeakReference weakReference = new WeakReference(o,referenceQueue);
        System.out.println(o);
        System.out.println(weakReference.get());
        System.out.println(referenceQueue.poll());
        o = null;
        System.out.println("=================");

        System.gc();
        Thread.sleep(500);
        System.out.println(o);
        System.out.println(weakReference.get());
        System.out.println(referenceQueue.poll());
    }
}

 

10. 内存溢出OutOfMemoryError 10.1 StackOverflowError

栈满会抛出该错误。无限递归就会导致StackOverflowError,是java.lang.Throwable→java.lang.Error→java.lang.VirtualMachineError下的错误。详见

package com.bcl.jvm;

public class StackOverFlowErrorDemo {
    public static void main(String[] args) {
        stackOverflowErr();
    }
    public static void stackOverflowErr(){
        stackOverflowErr();
    }
}
10.2 OOM—Java head space

堆满会抛出该错误。

package com.bcl.jvm;


public class HeapSpaceErrDemo {
    public static void main(String[] args) {
        byte[] bArr = new byte[60 * 1024 * 1024];
    }
}
10.3 OOM—GC overhead limit exceeded

这个错误是指:GC的时候会有“Stop the World",STW越小越好,正常情况是GC只会占到很少一部分时间。但是如果用超过98%的时间来做GC,而且收效甚微,就会被JVM叫停。下例中,执行了多次Full GC,但是内存回收很少,最后抛出了OOM:GC overhead limit exceeded错误。详见

备注:超过98%的时间用来gc,回收不到2%的内存,连续多次都是如此的极端情况,最后抛出异常OOM:GC overhead limit exceeded,如果不抛出该异常,会导致:gc清理出来的内存会很快被再次填满,迫使GC再次执行,这样就形成了恶性循环,cpu使用率一直是100%,而GC却没有任何成果

package com.bcl.jvm;

import java.util.ArrayList;
import java.util.List;


public class GCOverheadDemo {
    public static void main(String[] args) {
        int i = 0;
        List list = new ArrayList<>();
        try {
            while (true) {
                //如果常量池中已经有了此字符串,那么将常量池中该字符串的引用返回
                //Java7和Java8的intern方法作用:如果常量池没有,那么会将堆中的字符串的引用放到常量池,注意是引用,然后返回该引用。
                //为什么Java7和Java8会不一样呢,原因就是 Java7之后(部分虚拟机,Hotspot,JRockit)已经将永久代的常量池、静态变量移出,
                //放入了Java堆中,而永久代也在Java8中完全废弃,方法区改名为元空间
                list.add(String.valueOf(++i).intern());
            }
        } catch (Throwable e) {
            e.printStackTrace();
            System.out.println("***********************i:" + i);
            throw e;
        }
    }
}
[Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7084K->7084K(7168K)] 
9132K->9132K(9728K), [metaspace: 3313K->3313K(1056768K)], 0.0738461 secs] [Times: user=0.36 
sys=0.02, real=0.07 secs]

Exception in thread "main" [Full GC (Ergonomics) [PSYoungGen: 2047K->0K(2560K)] [ParOldGen: 
7119K->647K(7168K)] 9167K->647K(9728K), [metaspace: 3360K->3360K(1056768K)], 0.0129597 secs] [Times:
 user=0.11 sys=0.00, real=0.01 secs] java.lang.OutOfMemoryError: GC overhead limit exceeded at 
java.lang.Integer.toString(Integer.java:401) at java.lang.String.valueOf(String.java:3099) at 
jvm.GCOverheadDemo.main(GCOverheadDemo.java:12)
10.4 OOM—GC Direct buffer memory

在写NIO程序的时候,会用到ByteBuffer来读取和存入数据。与Java堆的数据不一样,ByteBuffer使用native方法,直接在堆外分配内存。当堆外内存(也即本地物理内存)不够时,就会抛出这个异常。

package com.bcl.jvm;

import java.nio.ByteBuffer;

public class DirectBufferMemoryDemo {
    public static void main(String[] args) {
        System.out.println("配置的maxDirectMemory:" + (sun.misc.VM.maxDirectMemory() / (double) 1024 / 1024) + "MB ");
        try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
        ByteBuffer.allocateDirect(6 * 1024 * 1024);
    }
}
10.5 OOM—unable to create new native thread

在高并发应用场景时,如果创建超过了系统默认的最大线程数,就会抛出该异常。Linux单个进程默认不能超过1024个线程。解决方法要么降低程序线程数,要么修改系统最大线程数vim /etc/security/limits.d/90-nproc.conf。详见

package com.bcl.jvm;


public class UnableCreateNewThreadDemo {
    public static void main(String[] args) {
        for(int i = 1;;i++){
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName()+":创建");
                try { Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); }
            },String.valueOf(i)).start();
        }
    }
}
10.6 OOM—metaspace

元空间满了就会抛出这个异常

package com.bcl.jvm;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;


public class metaSpaceOOMDemo {
    static class OOMTest {
    }

    public static void main(String[] args) {
        int i = 0;
        try {
            while (true) {
                i++;
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(OOMTest.class);
                enhancer.setUseCache(false);
                enhancer.setCallback(new MethodInterceptor() {
                    @Override
                    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                        return methodProxy.invoke(o, args);
                    }
                });
                enhancer.create();
            }
        } catch (Throwable e) {
            System.out.println("*****************多少次发生异常:" + i);
            e.printStackTrace();
        }
    }
}
11. 四大垃圾收集算法 11. 标记整理

11.2 标记清除

11.3 复制算法

11.4 分代收集算法

准确来讲,跟前面三种算法有所区别。分代收集算法就是根据对象的年代,采用上述三种算法来收集。

    对于新生代:每次GC都有大量对象死去,存活的很少,常采用复制算法,只需要拷贝很少的对象。对于老年代:常采用标整或者标清算法。
12. 四种垃圾收集器

Java 8可以将垃圾收集器分为四类。

12.1 串行收集器Serial

为单线程环境设计且只使用一个线程进行GC,会暂停所有用户线程,不适用于服务器。就像去餐厅吃饭,只有一个清洁工在打扫。

12.2 并行收集器Parrallel

使用多个线程并行地进行GC,会暂停所有用户线程,适用于科学计算、大数据后台,交互性不敏感的场合。多个清洁工同时在打扫。

12.3 并发收集器CMS

用户线程和GC线程同时执行(不一定是并行,交替执行),GC时不需要停顿用户线程,互联网公司多用,适用对响应时间有要求的场合。清洁工打扫的时候,也可以就餐。

12.4 G1收集器

对内存的划分与前面3种很大不同,将堆内存分割成不同的区域,然后并发地进行垃圾回收。

13. 默认垃圾收集器 13.1 默认收集器有哪些

有Serial、Parallel、ConcMarkSweep(CMS)、ParNew、ParallelOld、G1。还有一个SerialOld,快被淘汰了。

13.2 查看默认垃圾修改器

使用java -XX:+PrintCommandLineFlags即可看到,Java 8默认使用-XX:+UseParallelGC。

14. 七大垃圾收集器 14.1 体系结构

Serial、Parallel Scavenge、ParNew用户回收新生代;SerialOld、ParallelOld、CMS用于回收老年代。而G1收集器,既可以回收新生代,也可以回收老年代。

连线表示可以搭配使用,红叉表示不推荐一同使用,比如新生代用Serial,老年代用CMS。

14.2 Serial收集器

年代最久远,是Client VM模式下的默认新生代收集器,使用复制算法。优点:单个线程收集,没有线程切换开销,拥有最高的单线程GC效率。缺点:收集的时候会暂停用户线程。

使用-XX:+UseSerialGC可以显式开启,开启后默认使用Serial+SerialOld的组合。

-Xms5m -Xmx5m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseSerialGC
14.3 ParNew收集器

也就是Serial的多线程版本,GC的时候不再是一个线程,而是多个,是Server VM模式下的默认新生代收集器,采用复制算法。

使用-XX:+UseParNewGC可以显式开启,开启后默认使用ParNew+SerialOld的组合。但是由于SerialOld已经过时,所以建议配合CMS使用。

-Xms5m -Xmx5m -XX:+PrintGCDetails -XX:+PrintCommandLineFlags -XX:+UseParNewGC
14.3 Parallel Scavenge收集器

ParNew收集器仅在新生代使用多线程收集,老年代默认是SerialOld,所以是单线程收集。而Parallel Scavenge在新、老两代都采用多线程收集。Parallel Scavenge还有一个特点就是吞吐量优先收集器,可以通过自适应调节,保证最大吞吐量。采用复制算法。

使用-XX:+UseParallelGC可以开启, 同时也会使用ParallelOld收集老年代。其它参数,比如-XX:ParallelGCThreads=N可以选择N个线程进行GC,-XX:+UseAdaptiveSizePolicy使用自适应调节策略。

14.4 SerialOld收集器

Serial的老年代版本,采用标整算法。JDK1.5之前跟Parallel Scavenge配合使用,现在已经不了,作为CMS的后备收集器。

14.5 ParallelOld收集器

Parallel的老年代版本,JDK1.6之前,新生代用Parallel而老年代用SerialOld,只能保证新生代的吞吐量。JDK1.8后,老年代改用ParallelOld。

使用-XX:+UseParallelOldGC可以开启, 同时也会使用Parallel收集新生代。

14.6 CMS收集器

并发标记清除收集器,是一种以获得最短GC停顿为目标的收集器。适用在互联网或者B/S系统的服务器上,这类应用尤其重视服务器的响应速度,希望停顿时间最短。是G1收集器出来之前的首选收集器。使用标清算法。在GC的时候,会与用户线程并发执行,不会停顿用户线程。但是在标记的时候,仍然会STW。

使用-XX:+UseConcMarkSweepGC开启。开启过后,新生代默认使用ParNew,同时老年代使用SerialOld作为备用。

CMS工作过程:

    初始标记:只是标记一下GC Roots能直接关联的对象,速度很快,需要STW。并发标记:主要标记过程,标记全部对象,和用户线程一起工作,不需要STW。重新标记:修正在并发标记阶段出现的变动,需要STW。并发清除:和用户线程一起,清除垃圾,不需要STW。

CMS优缺点:

优点:停顿时间少,响应速度快,用户体验好。

缺点:

    对CPU资源非常敏感:由于需要并发工作,多少会占用系统线程资源。无法处理浮动垃圾:由于标记垃圾的时候,用户进程仍然在运行,无法有效处理新产生的垃圾。产生内存碎片:由于使用标清算法,会产生内存碎片。
14.7 G1收集器

G1收集器与之前垃圾收集器的一个显著区别就是——之前收集器都有三个区域,新、老两代和元空间。而G1收集器只有G1区和元空间。而G1区,不像之前的收集器,分为新、老两代,而是一个一个Region,每个Region既可能包含新生代,也可能包含老年代。

G1收集器既可以提高吞吐量,又可以减少GC时间。最重要的是STW可控,增加了预测机制,让用户指定停顿时间。

使用-XX:+UseG1GC开启,还有-XX:G1HeapRegionSize=n、-XX:MaxGCPauseMillis=n等参数可调。

G1特点:

    并行和并发:充分利用多核、多线程CPU,尽量缩短STW。分代收集:虽然还保留着新、老两代的概念,但物理上不再隔离,而是融合在Region中。空间整合:G1整体上看是标整算法,在局部看又是复制算法,不会产生内存碎片。可预测停顿:用户可以指定一个GC停顿时间,G1收集器会尽量满足。

**G1过程:**与CMS类似

    初始标记。并发标记。最终标记。筛选回收。
14.8 G1相对CMS优势

G1不会产生内存碎片是可以精确控制停顿时间,该收集器是把整个堆(新生代,老年代)划分成多个固定大小的区域,每次根据允许的停顿时间去回收垃圾最多的区域 15. JVM和SpringBoot

java -server -Xms1024m -Xmx1024m -XX:+PrintGCDetails -X:+UserG1GC -jar xxxx.jar

16. Linux相关指令 16.1 top

主要查看%CPU、%MEM,还有load average。load average后面的三个数字,表示系统1分钟、5分钟、15分钟的平均负载值。如果三者相加平均值高于0.6,则说明负载比较高了。当然,用uptime也可以查看。

16.2 vmstat

查看进程、内存、I/O等多个系统运行状态。2表示每两秒采样一次,3表示一共采样3次。procs的r表示运行和等待CPU时间片的进程数,原则上1核CPU不要超过2。b是等待资源的进程数,比如磁盘I/O、网络I/O等。

[root@sports-activity-test ~]# vmstat -n 2 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 250092 160648 2329308    0    0     0     3    2    0  1  1 98  0  0
 0  0      0 250092 160648 2329308    0    0     0    36 3357 3863  1  1 98  0  0
 0  0      0 250092 160648 2329308    0    0     0     0 3087 3756  1  1 99  0  0

16.3 mpstat

查看所有cpu信息

mpstat -P ALL 2 //每2s收集一次
16.4 pidstat

每个进程使用CPU的分解信息

pidstat -u 1 -p 403(进程号)
16.5 free

查看内存信息。

-   free  (kb)
-   free -m (一般采用)
-   free -g (四舍五入,不准确)
-   pidstat -p 进程号 -r 采样间隔秒数
16.6 df

查看磁盘信息。一般使用df -h ,因为df可读性差

Filesystem      Size  Used Avail Use% Mounted on
overlay         197G   68G  122G  36% /
tmpfs            64M     0   64M   0% /dev
tmpfs            31G     0   31G   0% /sys/fs/cgroup
/dev/vda1       197G   68G  122G  36% /etc/hosts
shm              64M     0   64M   0% /dev/shm
tmpfs            31G   12K   31G   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs            31G     0   31G   0% /proc/acpi
tmpfs            31G     0   31G   0% /proc/scsi
tmpfs            31G     0   31G   0% /sys/firmware
16.7 iostat

查看磁盘I/O信息。比如有时候MySQL在查表的时候,会占用大量磁盘I/O,体现在该指令的%util字段很大。对于死循环的程序,CPU占用固然很高,但是磁盘I/O不高。

16.8 ifstat

查看网络I/O信息,需要安装。

17. CPU占用过高原因定位

先用top找到CPU占用最高的进程,然后用ps -mp pid -o THREAD,tid,time,得到该进程里面占用最高的线程。这个线程是10进制的,将其转成16进制,然后用jstack pid | grep tid可以定位到具体哪一行导致了占用过高。

1.先用top命令找到cpu占用最高的

2.ps -ef或jps 进一步定位
ps-ef| grep java | grep -v grep    

3.定位到具体的线程,ps -map 进程ID -o THREAD,tid,time
ps -map 432 -o THREAD,tid,time
-m 显示所有的线程
-p pid进程使用的cpu的时间
-o 该参数是用户自定义的格式

4.将需要的pid转换为16进制的格式(英文小写格式)
printf "%xn" 有问题的线程ID
printf "%xn" 436

5.jstack 进程ID | grep tid(16进制的线程ID小写英文) -A60
jstack 432|grep 1b4 -A60
18. JVM性能调优和监控工具
    jps:Java版的ps -ef查看所有JVM进程。jstack:查看JVM中运行线程的状态,比较重要。可以定位CPU占用过高位置,定位死锁位置。jinfo/jstat:jinfo查看JVM的运行环境参数,比如默认的JVM参数等。jstat统计信息监视工具。jmap:JVM内存映像工具。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5719531.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)