五、JVM 调优工具


一、JDK 体系结构

java
javac
javadoc
javap -c Math.class > math.txt

# 反编译字节码文件
javap -c VolatileMain2.class 

jvisualvm

二、Jmap 内存图

[root@dam ~]# jps
2008 dam.jar
28667 Jps

[root@dam ~]# jmap -histo 2008 > ./log.txt
  • 此命令可以用来查看内存信息:
    在这里插入图片描述
  • num:序号
  • #instances:实例数量
  • #bytes:占用空间大小(字节)
  • class name:类名称
  1. [B:is a byte[]
  2. [S:is a short[]
  3. [C:is a char[]
  4. [I:is a int[]
  5. [[I:is a int[][]

1. 查看堆信息

[root@dam ~]# jps
1827 Jps
2008 dam.jar

[root@dam ~]# jmap -heap 2008

在这里插入图片描述

Attaching to process ID 2008, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.312-b07

using thread-local object allocation.
Parallel GC with 2 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 2051014656 (1956.0MB)
   NewSize                  = 42991616 (41.0MB)
   MaxNewSize               = 683671552 (652.0MB)
   OldSize                  = 87031808 (83.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 651165696 (621.0MB)
   used     = 180286232 (171.9343490600586MB)
   free     = 470879464 (449.0656509399414MB)
   27.686690669896713% used
From Space:
   capacity = 15728640 (15.0MB)
   used     = 1015808 (0.96875MB)
   free     = 14712832 (14.03125MB)
   6.458333333333333% used
To Space:
   capacity = 16252928 (15.5MB)
   used     = 0 (0.0MB)
   free     = 16252928 (15.5MB)
   0.0% used
PS Old Generation
   capacity = 191889408 (183.0MB)
   used     = 56952368 (54.31401062011719MB)
   free     = 134937040 (128.6859893798828MB)
   29.679787224107752% used

43450 interned Strings occupying 4151912 bytes.

2. 导出堆快照

# 运行时
jmap -dump:live,format=b,life=<'filepath'> <'pid'>

  • -Xmx128m:设置堆内存
  • -XX:+HeapDumpOnOutOfMemoryError:启动时开启堆错误快照
  • -XX:HeapDumpPath=./:堆错误快照指定路径
[root@dam ~]# jps
1827 Jps
2008 dam.jar

# 设置内存溢出,自动导出`dump`文件(内存很大的时候,可能会导不出来)。
[root@dam ~]# jmap -dump:format=b,file=dam.hprof 2008

  • 分析堆快照
  1. MAT
  2. VisualVM
  3. JProfiler

3. jvisualvm 工具分析 dump 文件

C:\Users\qshome>jvisualvm
  • 可以用 jvisualvm 命令工具,导入 dump 文件进行分析:
    在这里插入图片描述
    在这里插入图片描述

三、Jstack 查找死锁

# 死锁-定位进程号
jps -l     
# 死锁-查看进程信息  
jstack pid   

/**
 * 死锁
 * @author wy
 */
public class LockTest2 {

    private static Object lock1 = new Object();
    private static Object lock2 = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            String threadName = Thread.currentThread().getName();
            synchronized (lock1) {
                System.out.printf("线程:%s 运行", threadName).println();
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock2) {
                    System.out.printf("线程:%s 结束", threadName).println();
                }
            }
        }).start();

        new Thread(() -> {
            String threadName = Thread.currentThread().getName();
            synchronized (lock2) {
                System.out.printf("线程:%s 运行", threadName).println();
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lock1) {
                    System.out.printf("线程:%s 结束", threadName).println();
                }
            }
        }).start();

        System.out.printf("线程:%s 结束", Thread.currentThread().getName()).println();
    }
}

1. jvisualvm 工具检测死锁

  • 可以用 jvisualvm 自动检测死锁:
    在这里插入图片描述

2. jvisualvm 工具远程连接

  • jvisualvm 工具,远程连接服务:
    需要在远程服务器上配置 Host(连接 IP 主机名),并且要关闭防火墙。

  1. jar 程序,配置 JMX 端口:
# `jar`程序,配置`JMX`端口。
java -jar foo.jar \
-Dcom.sun.management.jmxremote.port=8899 \ 
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false 

  1. Tomcat 配置 JMX 端口:
# `Tomcat`配置`JMX`端口。
JAVA_OPTS=-Dcom.sun.management.jmxremote.port=8899 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false

3. Jstack 找出占用 CPU 最高的堆栈信息

[root@dam ~]# jps
7153 Jps
2008 dam.jar

# 1. 显示`Java`进程的内存情况
[root@dam ~]# top -p 2008
  • top -p <pid>:显示 Java 进程的内存情况(<pid> 进程号)。
    在这里插入图片描述
# 2. 获取每个线程的内存情况。
[root@qs ~]# H
  • 找到内存和 CPU 占用最高的线程 tid(比如:2008,转为十六进制:0x7d8)。
    在这里插入图片描述
  • 查看对应的堆栈信息,找出可能存在问题的代码。
# 3. 得到线程堆栈信息中,线程`7d8`所在行的后`10`行。
jstack 2008 | grep -A 10 7d8

四、Jinfo 扩展参数

  • 查看正在运行的 Java 应用程序的扩展参数。

1. 查看 JVM 的参数

[root@dam ~]# jps
2008 dam.jar
1400 Jps

[root@dam ~]# jinfo -flags 2008

在这里插入图片描述


2. 查看 Java 系统参数

[root@dam ~]# jps
30613 Jps
2008 dam.jar

[root@dam ~]# jinfo -sysprops 2008

在这里插入图片描述


五、Jstat 查看堆内存使用量【常用】

  • jstat 命令,查看堆内存各部分的使用量,以及加载类的数量。
  • 注意:使用的 JDK-8 版本。
# jstat [-命令选项] [vmid] [间隔时间(毫秒)] [查询次数]

1. 垃圾回收统计

[root@dam ~]# jps
14032 Jps
2008 dam.jar

[root@dam ~]# jstat -gc 2008

在这里插入图片描述

  • S0C:第一个幸存区的大小。
  • S1C:第二个幸存区的大小。
  • S0U:第一个幸存区的使用大小。
  • S1U:第二个幸存区的使用大小。
  • EC:伊甸园区的大小。
  • EU:伊甸园区的使用大小。
  • OC:老年代大小。
  • OU:老年代使用大小。
  • MC:方法区大小(元空间)。
  • MU:方法区使用大小。
  • CCSC:压缩类空间大小。
  • CCSU:压缩类空间使用大小。
  • YGC:年轻代垃圾回收次数。
  • YGCT:年轻代垃圾回收消耗时间(单位s)。
  • FGC:老年代垃圾回收次数。
  • FGCT:老年代垃圾回收消耗时间(单位s)。
  • GCT:垃圾回收消耗总时间(单位s)。

2. 堆内存统计

[root@dam ~]# jps
25729 Jps
2008 dam.jar

[root@dam ~]# jstat -gccapacity 2008

在这里插入图片描述

  • NGCMN:新生代最小容量。
  • NGCMX:新生代最大容量。
  • NGC:当前新生代容量。
  • S0C:第一个幸存区大小。
  • S1C:第二个幸存区的大小。
  • EC:伊甸园区的大小。
  • OGCMN:老年代最小容量。
  • OGCMX:老年代最大容量。
  • OGC:当前老年代大小。
  • OC:当前老年代大小。
  • MCMN:最小元数据容量。
  • MCMX:最大元数据容量。
  • MC:当前元数据空间大小。
  • CCSMN:最小压缩类空间大小。
  • CCSMX:最大压缩类空间大小。
  • CCSC:当前压缩类空间大小。
  • YGC:年轻代 GC 次数。
  • FGC:老年代 GC 次数。

3. 新生代垃圾回收统计

[root@dam ~]# jps
2008 dam.jar
3839 Jps

[root@dam ~]# jstat -gcnew 2008

在这里插入图片描述

  • S0C:第一个幸存区的大小。
  • S1C:第二个幸存区的大小。
  • S0U:第一个幸存区的使用大小。
  • S1U:第二个幸存区的使用大小。
  • TT:对象在新生代存活的次数。
  • MTT:对象在新生代存活的最大次数。
  • DSS:期望的幸存区大小。
  • EC:伊甸园区的大小。
  • EU:伊甸园区的使用大小。
  • YGC:年轻代垃圾回收次数。
  • YGCT:年轻代垃圾回收消耗时间。

4. 新生代内存统计

[root@dam ~]# jps
2008 dam.jar
15389 Jps

[root@dam ~]# jstat -gcnewcapacity 2008

在这里插入图片描述

  • NGCMN:新生代最小容量。
  • NGCMX:新生代最大容量。
  • NGC:当前新生代容量。
  • S0CMX:最大幸存1区大小。
  • S0C:当前幸存1区大小。
  • S1CMX:最大幸存2区大小。
  • S1C:当前幸存2区大小。
  • ECMX:最大伊甸园区大小。
  • EC:当前伊甸园区大小。
  • YGC:年轻代垃圾回收次数。
  • FGC:老年代回收次数。

5. 老年代垃圾回收统计

[root@dam ~]# jps
2008 dam.jar
22607 Jps

[root@dam ~]# jstat -gcold 2008

在这里插入图片描述

  • MC:方法区大小。
  • MU:方法区使用大小。
  • CCSC:压缩类空间大小。
  • CCSU:压缩类空间使用大小。
  • OC:老年代大小。
  • OU:老年代使用大小。
  • YGC:年轻代垃圾回收次数。
  • FGC:老年代垃圾回收次数。
  • FGCT:老年代垃圾回收消耗时间。
  • GCT:垃圾回收消耗总时间。

6. 老年代内存统计

[root@dam ~]# jps
2008 dam.jar
6558 Jps

[root@dam ~]# jstat -gcoldcapacity 2008

在这里插入图片描述

  • OGCMN:老年代最小容量。
  • OGCMX:老年代最大容量。
  • OGC:当前老年代大小。
  • OC:老年代大小。
  • YGC:年轻代垃圾回收次数。
  • FGC:老年代垃圾回收次数。
  • FGCT:老年代垃圾回收消耗时间。
  • GCT:垃圾回收消耗总时间。

7. 元数据空间统计

[root@dam ~]# jps
2008 dam.jar
14921 Jps

[root@dam ~]# jstat -gcmetacapacity 2008

在这里插入图片描述

  • MCMN:最小元数据容量。
  • MCMX:最大元数据容量。
  • MC:当前元数据空间大小。
  • CCSMN:最小压缩类空间大小。
  • CCSMX:最大压缩类空间大小。
  • CCSC:当前压缩类空间大小。
  • YGC:年轻代垃圾回收次数。
  • FGC:老年代垃圾回收次数。
  • FGCT:老年代垃圾回收消耗时间。
  • GCT:垃圾回收消耗总时间。

[root@dam ~]# jps
20384 Jps
2008 dam.jar

[root@dam ~]# jstat -gcutil 2008

在这里插入图片描述

  • S0:幸存1区当前使用比例。
  • S1:幸存2区当前使用比例。
  • E:伊甸园区使用比例。
  • O:老年代使用比例。
  • M:元数据区使用比例。
  • CCS:压缩使用比例。
  • YGC:年轻代垃圾回收次数。
  • FGC:老年代垃圾回收次数。
  • FGCT:老年代垃圾回收消耗时间。
  • GCT:垃圾回收消耗总时间。

六、JVM 运行情况预估

  • JVM 优化参数。
  1. 堆内存大小。
  2. 年轻代大小。
  3. EdenSurvivor 区的比例。
  4. 老年代的大小。
  5. 大对象的阈值。
  6. 大龄对象进入老年代的阈值等。

  • JVM 优化思路。
  1. 尽量让每次 YoungGC 后的存活对象,小于 Survivor 区域的 50%
  2. 尽量让对象,都留存在年轻代里。
  3. 尽量别让对象,进入老年代。
  4. 尽量减少 FullGC 的频率,避免频繁 FullGCJVM 性能的影响。

1. 年轻代对象增长的速率

[root@dam ~]# jps
27777 Jps
2008 dam.jar

# 每隔`1`秒执行`1`次命令,共执行`10`次。
[root@dam ~]# jstat -gc 2008 1000 10
  • 每隔 1 秒执行 1 次命令,共执行 10 次。
    在这里插入图片描述
  • 观察 Eden 区的使用,来估算每秒 Eden 区大概新增多少对象。
  • 如果系统负载不高,可以把频率 1 秒换成 1 分钟,甚至 10 分钟来观察整体情况。
  • 注意,一般系统可能有高峰期和日常期,所以需要在不同的时间,分别估算不同情况下对象增长速率。

2. YoungGC 的触发频率和每次耗时

  • 知道年轻代对象增长速率,就能根据 Eden 区的大小,推算出 YoungGC 大概多久触发一次。
  • YoungGC 的平均耗时,可以通过 YGCT/YGC 公式算出
  • 根据结果大概就能知道,系统大概多久会因为 YoungGC 的执行而卡顿多久

3. 每次 YoungGC 后有多少对象存活和进入老年代

[root@dam ~]# jps
27777 Jps
2008 dam.jar

# 每隔`5`分钟执行`1`次命令,共执行`10`次。
[root@dam ~]# jstat -gc 2008 300000 10
  • 知道 YoungGC 的频率,假设是每 5 分钟一次,观察每次 EdenSurvivor 区 和 老年代 使用的变化情况。
  • 在每次 GCEden 区使用一般会大幅减少,Survivor 和 老年代 都有可能增长,这些增长的对象就是每次 YoungGC 后存活的对象。
  • 同时还可以看出每次 YoungGC 后进入老年代大概多少对象,从而可以推算出老年代对象增长速率。

4. FullGC 的触发频率和每次耗时

  • 知道老年代对象的增长速率,就可以推算出 FullGC 的触发频率了。
  • FullGC 的每次耗时,可以用公式 FGCT/FGC 计算得出

七、JVM 调优概念

  1. 尽可能让对象,都在 新生代 里分配和回收。
  2. 尽量别让太多对象,频繁进入 老年代,避免频繁对 老年代 进行垃圾回收。
  3. 同时给系统充足的内存大小,避免 新生代 频繁的进行垃圾回收。

1. JVM 相关参数

-Dcatalina.home=E:\tools\tomcat\apache-tomcat-7.0.67
-Dcatalina.base=E:\tools\tomcat\apache-tomcat-7.0.67
-Djava.endorsed.dirs=E:\tools\tomcat\apache-tomcat-7.0.67\endorsed
-Djava.io.tmpdir=E:\tools\tomcat\apache-tomcat-7.0.67\temp
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager

# 堆溢出异常
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=E:\tools\tomcat\apache-tomcat-7.0.67\bin\java_heapdump.hprof
-Djava.util.logging.config.file=E:\tools\tomcat\apache-tomcat-7.0.67\conf\logging.properties
-javaagent:E:\tools\tanzhen\tingyun\tingyun-agent-java.jar

# `FullGC`异常
-XX:+HeapDumpBeforeFullGC
-XX:+HeapDumpAfterFullGC
-XX:NewSize=6144M

# 元空间
-XX:MetaspaceSize=1024M
-XX:MaxMetaspaceSize=2048M

# 堆总大小
-Xms1536M
# 堆最大大小
-Xmx1536M

# 堆新生代大小
-Xmn512M
-Xmn1024M

# 栈大小
-Xss256K

# 新生代比率(6 : 1 : 1)
-XX:SurvivorRatio=6

# 方法区
-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=256M

# 新生代`GC`
-XX:+UseParNewGC

# CMS(老年代`75%`触发`FULLGC`)
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:CMSInitiatingOccupancyFraction=92
-XX:+UseCMSInitiatingOccupancyOnly

2. 参数案例

java -jar test.jar
# 堆`3G`
# 年轻代:`Eden=800M`、`S0=100M`、`S1:100M`
# 老年代:`Old=2G`
-Xms3G \
-Xmx3G \
-Xss1M \
-XX:MetaspaceSize=512M \
-XX:MaxMetaspaseSize=512M

java -jar test.jar
# 堆`3G`
# 年轻代:`Eden=1.6G`、`S0=200M`、`S1=200M`
# 老年代:`Old=1G`
-Xms3G \
-Xmx3G \
-Xmn2G \
-Xss1M \
-XX:MetaspaceSize=512M \
-XX:MaxMetaspaseSize=512M 

八、JVM 调优案例


1. 系统频繁 FullGC 导致系统卡顿

  • 机器配置:双核4G。
  • JVM 内存大小:2G。
  • 系统运行时间:7天。
  • 期间发生的 FullGC 次数和耗时:500多次,200多秒。
  • 期间发生的 YoungGC 次数和耗时:1万多次,500多秒。

  • 大致估算每天会发生 70 多次 FullGC,平均每小时 3 次,每次 FullGC400 毫秒左右。
  • 每天会发生 1000 多次 YoungGC,每分钟会发生 1 次,每次 YoungGC50 毫秒左右。

  • JVM 调优参数。
‐Xms1536M \
‐Xmx1536M \
‐Xmn512M \
‐Xss256K \
‐XX:SurvivorRatio=6 \
‐XX:MetaspaceSize=256M \
‐XX:MaxMetaspaceSize=256M \
‐XX:+UseParNewGC \
‐XX:+UseConcMarkSweepGC \
‐XX:CMSInitiatingOccupancyFraction=75 \
‐XX:+UseCMSInitiatingOccupancyOnly
  • 结合对象挪动到老年代的规则,推理程序可能存在的一些问题。
    在这里插入图片描述

  • 打印 jstat 的结果。
    在这里插入图片描述
  1. YoungGCFullGC 都太频繁了。
  2. 有大量的对象,频繁的被挪动到老年代。

  • 打印 jmap 的结果。
    在这里插入图片描述
/**
 * @author wy
 * describe
 */
@RestController
public class IndexController {

    @GetMapping("/getPersons")
    public String getPersons() {
        List<Person> persons = queryPersons();
        for (Person person : persons) {
            System.out.println(person);
        }
        return "Success";
    }

    /**
     * 模拟批量查询用户
     */
    private List<Person> queryPersons() {
        List<Person> persons = new ArrayList<>();
        for (int i = 0; i < 5000; i++) {
            persons.add(new Person(String.valueOf(i++), 18));
        }
        return persons;
    }
}

  • JVM 调优参数。
‐Xms1536M \
‐Xmx1536M \
‐Xmn1024M \
‐Xss256K \
‐XX:SurvivorRatio=6 \
‐XX:MetaspaceSize=256M \
‐XX:MaxMetaspaceSize=256M \
‐XX:+UseParNewGC \
‐XX:+UseConcMarkSweepGC \
‐XX:CMSInitiatingOccupancyFraction=92 \
‐XX:+UseCMSInitiatingOccupancyOnly
  • Java 的代码也是需要优化的,一次查询出 500M 的对象出来,明显不合适。
  • 要根据各种原则尽量优化到合适的值,尽量消除这种朝生夕死的对象导致的 FullGC
    在这里插入图片描述

2. OOM 调优

java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: Java metaspace
java.lang.OutOfMemoryError: Java perm gen
java.lang.OutOfMemoryError: GC overhead limit exceeded

# 垃圾回收统计
jstat -gc 30046

# 新生代
jstat -gcnew 30046

# 老年代
jstat -gcold 30046

# 元空间
jstat -gcmetacapacity 30046

[root@DB ~]# jps
20697 qs-1.0.jar
21759 Jps
[root@DB ~]# jstat -gc 20697

---

 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
17920.0 20480.0 16880.1  0.0   279552.0 36980.2   84992.0    40565.8   71424.0 68320.8 8960.0 8407.2     18    0.275   3      0.249    0.523
106496.0 106496.0  0.0    0.0   107520.0 107520.0  642048.0   630045.5  81920.0 77122.4 10240.0 9415.6    209    6.728  134    97.947  104.675

 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
131072.0 131072.0  0.0   44847.0 786432.0 761630.0  524288.0     0.0     56448.0 53894.1 7296.0 6756.6      3    0.229   0      0.000    0.229
131072.0 131072.0  0.0   121469.0 786432.0 786432.0  524288.0   475417.2  81920.0 77610.7 10240.0 9475.0     25    3.058   5      1.409    4.468
131072.0 131072.0  0.0    0.0   786432.0 733991.6  524288.0   478621.7  81920.0 77286.1 10240.0 9428.9     36    3.578  48     29.893   33.470

S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
131072.0 131072.0  0.0   44688.1 786432.0 749633.6  524288.0     0.0     56448.0 53866.6 7296.0 6759.5      3    0.256   0      0.000    0.256
131072.0 131072.0  0.0    0.0   786432.0 221083.2  524288.0   524288.0  81664.0 77483.7 10240.0 9466.5     23    3.125  13      7.530   10.656
131072.0 131072.0 131072.0  0.0   786432.0 786432.0  524288.0   517821.8  82176.0 77772.3 10240.0 9500.5     27    3.289  98     80.753   84.042

# 修改后
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
131072.0 131072.0  0.0   44712.8 786432.0 766408.2  524288.0     0.0     56192.0 53799.1 7296.0 6753.7      3    0.236   0      0.000    0.236
131072.0 131072.0 87523.0  0.0   786432.0 741640.9 1048576.0   767878.5  81664.0 77347.5 10240.0 9472.9     45    5.594  10      3.956    9.550

# 4G 对比 8G
S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
131072.0 131072.0  0.0    0.0   786432.0 235652.1  524288.0   57379.7   87168.0 82038.8 10624.0 9826.2     67    5.968 16040 3325.389 3331.357
166912.0 174080.0  0.0   75378.4 253952.0 52146.1  1316352.0  1030067.7  81792.0 77861.7 10112.0 9472.5    254    8.709  31     27.906   36.615

nohup java \ 
	-XX:+HeapDumpOnOutOfMemoryError \
	# 堆总大小
	-Xms1536M \
	# 堆最大大小
	-Xmx2048M \
	# 堆新生代大小
	-Xmn1024M \
	# 栈大小
	-Xss256K \
	# 新生代比率(6 : 1 : 1)
	-XX:SurvivorRatio=6 \
	# 方法区
	-XX:MetaspaceSize=256M \
	-XX:MaxMetaspaceSize=256M \
	# 新生代`GC`
	-XX:+UseParNewGC \
	# CMS(老年代`92%`触发`FULLGC`)
	-XX:+UseConcMarkSweepGC \
	-XX:CMSInitiatingOccupancyFraction=92 \
	-XX:+UseCMSInitiatingOccupancyOnly \
	-jar ./qs-0.0.1.jar \
	--server.port=9000 \
	>running.log &


九、JVM 优化扩展


1. 内存泄露

  • 一般电商架构可能会使用多级缓存架构,就是 Redis 加上 JVM 级缓存。
  1. 大多可能为了图方便,对于 JVM 级缓存就简单使用一个 HashMap,于是不断往里面放缓存数据。
  2. 但是很少考虑这个 Map 的容量问题,结果这个缓存 Map 越来越大,一直占用着老年代的很多空间。
  3. 时间长了就会导致 FullGC 非常频繁,这就是一种内存泄漏。
  4. 对于一些老旧数据没有及时清理,导致一直占用着宝贵的内存资源。
  5. 时间长了除了导致 FullGC,还有可能导致 OOM
  • 这种情况完全可以考虑采用一些成熟的 JVM 级缓存框架来解决。
    比如:Ehcache 等自带一些 LRU 数据淘汰算法的框架,来作为 JVM 级的缓存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骑士梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值