美文网首页编程笔记
内存溢出不可怕,手足无措才尴尬

内存溢出不可怕,手足无措才尴尬

作者: 老瓦在霸都 | 来源:发表于2020-01-27 15:39 被阅读0次

    内存溢出错误简称OOM,也就是 Out Of Memory Error , 是Java中常见也是最严重的错误之一. C及 C++程序最烦人的内存泄漏和溢出错误,在Java程序中由于垃圾回收似乎已经不存在了,其实不然,它一直都在。

    前一阵子,产品线就出现了一个内存溢出的问题,结合实例,总结回顾一下此类问题的原因和分析方法。

    1. 原因

    先来看看 Java 所使用的内存空间,Java虚拟机将内存分为如下5个区域:

    # 内存区域 线程私有 说明
    1 Method Area - 方法区 也称为永久区,保存类的元数据,包括类型信息,常量池,域变量信息,方法信息等
    2 Heap - 堆内存 存放 Java对象实例的内存池,由垃圾收集回收,通常按新生代和老年代进行分代收集
    3 JVM Language Stacks - Java 语言栈 栈的基本数据结构是栈帧Stack Frame, 存放了方法的局部变量表,操作数栈,动态连接方法和返回地址等
    4 PC Registers - Program Counter Registers 程序计数寄存器 处理器内部的寄存器,记录正在执行的Java字节码地址
    5 Native Method Stacks - 本地方法栈 用于其他语言实现的本地方法

    如下图所示

    JVM Spec

    我们在写程序时,如果用到了递归,要注意避免调用层次过深,否则会引起 StackOverFlowError,也可用-Xss参数来调整栈空间大小。而更为常见的 OutOfMemory 内存溢出错误,一般来说有如下常见的原因:

    1. JVM 的本地内存(native memory)耗尽
    2. Java 堆内存耗尽
    3. 永久代(java7)或元空间(Java8以上) 内存耗尽
    4. JVM 花费了太长时间进行垃圾收集(超过98%的时间用于GC或在整个GC期间,只有不到2%的堆被回收)

    2. 实例

    让我们写几个实际的例子来演示这个内存溢出错误,并分析其原因和分析的方法

    • 例一:分配超大数组造成 OOM
      执行 ./run_oom_demo.sh heap 10000000
        // java.lang.OutOfMemoryError:Java heap space
        public void noHeapSpace() {
            Integer[] array = new Integer[this.loopCount];
        }
    
    
    • 例二:创建过多类造成 OOM
      执行 ./run_oom_demo.sh meta 10000000
        //java.lang.OutOfMemoryError: Metaspace or PermSpace
        public void noMetaSpace() throws CannotCompileException {
            for (int i = 0; i < this.loopCount; i++) {
                Class c = classPool.makeClass("com.github.walterfan.hellometrics.OomDemo" + i).toClass();
                log.info("{}. makeClass {}", i, c.getName());
            }
        }
    
    • 例三:分配过多线程造成 OOM
      执行 ./run_oom_demo.sh native 10000000
        // java.lang.OutOfMemoryError: unable to create new native thread
        public void noNativeMemory() {
            for (int i = 0; i < this.loopCount; ++i) {
                new Thread() {
                    public void run() {
                        try {
                            Thread.sleep(1000000);
                        } catch(InterruptedException e) { }
                    }
                }.start();
                log.info("Thread " + i + " created");
            }
        }
    
    
    • 例四:错误使用 Multimap 造成OOM
      这个例子稍微复杂一些,本来是想要统计全球有多少种常用语言,使用这些语言是哪些国家和地区。
      因为语言和国家是有限的,所以用 map 来存储,并且也没有在使用过后进行清除。一开始,使用 Map<String, Set<String>> langCountriesMap = new HashMap<>() 来存储,因为 Set 不会保存重复的记录,所以无论运行多少次,都不会造成内存溢出。
      后来,为了简化代码,将 Map<String, Set<String>> 换成 Multimap<String, String>,没有考虑到 Guava 库的这个数据结构是value 不是想象中的 Set<String> ,而是一个 List<String> ,这样内存会随着调用次数的增加不断增长。

    代码如下:

        private Multimap<String, String>  localeMultiMap = ArrayListMultimap.create();
        private Map<String, Set<String>> langCountriesMap = new HashMap<>();
    
        // java.lang.OutOfMemoryError: Java heap space
        private void noHeapDemo() {
            for(long i =0; i < loopCount; ++i) {
                for(Locale locale: Locale.getAvailableLocales()) {
                    this.addLocale(locale.getLanguage(), locale.getCountry());
                    log.debug("{}/{}. {}", i, totalCount, locale);
                }
            }
            wait4Input(totalCount + " added, exit?");
            printLocales();
        }
    
        public void addLocale(String key, String value) {
    
            if(Strings.isBlank(key) || Strings.isBlank(value)) {
                return;
            }
            totalCount++;
            log.debug("addLocale {} -> {}", key, value);
            if("multimap".equals(demoType)) {
                this.localeMultiMap.put(key, value);
            } else {
                Set<String> countries = langCountriesMap.get(key);
                if(null == countries) {
                    countries = new HashSet<>();
                    langCountriesMap.put(key, countries);
                }
                countries.add(value);
            }
        }
    

    1)先用Map<String, Set<String>> 来存储,执行命令 ./run_oom_demo.sh hashmap 10000000, 一切正常,有如下输出。

    java -server -Xms128m -Xmx256m -XX:MaxMetaspaceSize=64m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./heapdump_2020-01-27_12_52_02.hprof -verbosegc -XX:+UseParallelGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+PrintGCDateStamps -Xloggc:./gc.log -XX:StringTableSize=100003 -Dsun.net.inetaddr.ttl=15 -Djava.security.egd=file:/dev/./urandom -Duser.timezone=GMT -Dfile.encoding=UTF8 -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=8091 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.password.file=./jmxremote.password -Dcom.sun.management.jmxremote.access.file=./jmxremote.access -cp ./target/hellometrics-1.0-SNAPSHOT-jar-with-dependencies.jar com.github.walterfan.hellometrics.OomDemo -t hashmap -c 10000000
    178  [main] INFO  c.g.walterfan.hellometrics.OomDemo - --- run demo hashmap ---
    1140000000 added, exit?
    81054 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 1. language: ar, countries: EG,AE,JO,SY,BH,IQ,YE,KW,LY,SA,QA,SD,MA,DZ,LB,TN,OM
    81055 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 2. language: be, countries: BY
    81055 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 3. language: bg, countries: BG
    81055 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 4. language: ca, countries: ES
    81055 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 5. language: cs, countries: CZ
    81055 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 6. language: da, countries: DK
    81055 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 7. language: de, countries: DE,AT,CH,LU,GR
    81055 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 8. language: el, countries: CY,GR
    81056 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 9. language: en, countries: SG,AU,IN,MT,ZA,PH,GB,NZ,IE,US,CA
    81056 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 10. language: es, countries: PR,SV,UY,HN,PY,CL,MX,DO,CO,BO,GT,ES,VE,CR,PA,AR,CU,PE,NI,EC,US
    81056 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 11. language: et, countries: EE
    81056 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 12. language: fi, countries: FI
    81056 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 13. language: fr, countries: BE,CH,LU,FR,CA
    81056 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 14. language: ga, countries: IE
    81056 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 15. language: hi, countries: IN
    81056 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 16. language: hr, countries: HR
    81056 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 17. language: hu, countries: HU
    81057 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 18. language: in, countries: ID
    81057 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 19. language: is, countries: IS
    81057 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 20. language: it, countries: CH,IT
    81057 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 21. language: iw, countries: IL
    81057 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 22. language: ja, countries: JP
    81057 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 23. language: ko, countries: KR
    81058 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 24. language: lt, countries: LT
    81058 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 25. language: lv, countries: LV
    81058 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 26. language: mk, countries: MK
    81058 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 27. language: ms, countries: MY
    81058 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 28. language: mt, countries: MT
    81059 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 29. language: nl, countries: BE,NL
    81059 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 30. language: no, countries: NO
    81059 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 31. language: pl, countries: PL
    81059 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 32. language: pt, countries: BR,PT
    81059 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 33. language: ro, countries: RO
    81059 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 34. language: ru, countries: RU
    81059 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 35. language: sk, countries: SK
    81060 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 36. language: sl, countries: SI
    81060 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 37. language: sq, countries: AL
    81060 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 38. language: sr, countries: CS,RS,ME,BA
    81060 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 39. language: sv, countries: SE
    81060 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 40. language: th, countries: TH
    81060 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 41. language: tr, countries: TR
    81061 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 42. language: uk, countries: UA
    81061 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 43. language: vi, countries: VN
    81061 [main] INFO  c.g.walterfan.hellometrics.OomDemo - 44. language: zh, countries: TW,HK,SG,CN
    Used memory: 42m
    

    2)然后再改用 Multimap, 执行命令 ./run_oom_demo.sh multimap 10000000

    $ ./run_oom_demo.sh multimap 10000000
    java -server -Xms128m -Xmx256m -XX:MaxMetaspaceSize=64m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./heapdump_2020-01-27_13_02_08.hprof -verbosegc -XX:+UseParallelGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+PrintGCDateStamps -Xloggc:./gc.log -XX:StringTableSize=100003 -Dsun.net.inetaddr.ttl=15 -Djava.security.egd=file:/dev/./urandom -Duser.timezone=GMT -Dfile.encoding=UTF8 -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=8091 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.password.file=./jmxremote.password -Dcom.sun.management.jmxremote.access.file=./jmxremote.access -cp ./target/hellometrics-1.0-SNAPSHOT-jar-with-dependencies.jar com.github.walterfan.hellometrics.OomDemo -t multimap -c 10000000
    156  [main] INFO  c.g.walterfan.hellometrics.OomDemo - --- run demo multimap ---
    java.lang.OutOfMemoryError: Java heap space
    Dumping heap to ./heapdump_2020-01-27_13_02_08.hprof ...
    Heap dump file created [424123288 bytes in 0.779 secs]
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays.copyOf(Arrays.java:3181)
        at java.util.ArrayList.grow(ArrayList.java:265)
        at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
        at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
        at java.util.ArrayList.add(ArrayList.java:462)
        at com.google.common.collect.AbstractMapBasedMultimap.put(AbstractMapBasedMultimap.java:202)
        at com.google.common.collect.AbstractListMultimap.put(AbstractListMultimap.java:100)
        at com.google.common.collect.ArrayListMultimap.put(ArrayListMultimap.java:66)
        at com.github.walterfan.hellometrics.OomDemo.addLocale(OomDemo.java:48)
        at com.github.walterfan.hellometrics.OomDemo.noHeapDemo(OomDemo.java:114)
        at com.github.walterfan.hellometrics.OomDemo.run(OomDemo.java:103)
        at com.github.walterfan.hellometrics.OomDemo.launchTool(OomDemo.java:159)
        at com.github.walterfan.hellometrics.OomDemo.main(OomDemo.java:190)
    

    发生了内存溢出,第一时间就要察看上述的日志输出,找出导致内存溢出的地方,有时情况没有这么简单,内存泄漏存在多处并且是缓慢累积而成的。这时,我们要分析堆转储文件

    用三种方法可以生成堆转储文件:

    • 1)使用jmap -dump选项在运行时获取堆转储比如 jmap -dump:format=b,file=/tmp/heap.hprof $pid 来导出 heap dump file。
    • 2)使用 jconsole 选项通过 HotSpotDiagnosticMXBean 获取堆转储。
      1. 通过指定-XX:+ HeapDumpOnOutOfMemoryError VM选项引发OutOfMemoryError时,将生成堆转储;

    这里我们用 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./heapdump.hprof 这两个启动选项让JVM 在内存溢出时生成堆转储文件

    3. 分析

    JDK 自带的 jhat 和 jvisualvm 都可以对 heap dump file 进行分析,最给力的工具当属 eclipse 出品的 内存分析工具 MAT(Memory Analyzer Tool)

    1) jvisualvm

    以 jvisualvm 为例, 执行命令 jvisualvm, 在 File 菜单中选取 Load 来打开堆转储文件

    load heap dump file

    可以看到这个堆转储文件的大体情况:

    heap dump summary

    内存溢出异常的线程调用栈:

    thread call stack

    而最有问题的是 Multimap中的值是一个 List<String> 存放的是国家名,占用绝大部分的内存:

    heap dump classes

    2) jhat

    jhat 是 JDK 自带的命令,它可以解析Java堆转储文件并启动一个Web服务器。 其默认侦听端口是7000, 可以通过 --port 参数改成其他端口。 jhat支持预先设计的查询(例如“显示已知类“ Foo”的所有实例”)以及OQL(对象查询语言)(一种类似于SQL的查询语言,用于查询堆转储)

    执行命令 jhat -J-mx1512m -port 2020 heapdump_2020-01-27_13_02_08.hprof
    用浏览器打开 http://localhost:2020, 内容与上面的 jvisualvm 所产生的内容差不多, 在此略过。
    打开 http://localhost:2020/oqlhelp/ 可以获取 OQL 的帮助

    3) mat

    MAT(Memory Analyzer Tool)是 Eclipse 著名的内存分析工具,它是一种快速且功能丰富的Java堆分析器,可用来查找内存泄漏并减少内存消耗,它可以用来分析包含数亿个对象的堆转储文件,快速计算对象的保留大小,查看谁阻止垃圾收集器进行垃圾回收,产生报告以自动报告可疑的内存泄漏。

    它的内存泄漏报告尤其有用:


    例如本例中的Multimap的内存问题就可以快速的诊断出来:

    4.实例的完整源代码

    1. 类 OomDemo.java
    package com.github.walterfan.hellometrics;
    
    import com.google.common.collect.ArrayListMultimap;
    import com.google.common.collect.Multimap;
    import javassist.CannotCompileException;
    import javassist.ClassPool;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.cli.*;
    import org.apache.commons.lang3.math.NumberUtils;
    import org.apache.logging.log4j.util.Strings;
    
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.*;
    
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.stream.Collectors;
    
    /**
     * @Author: Walter Fan
     * @Date: 22/1/2020, Wed
     **/
    @Slf4j
    public class OomDemo {
        private static ClassPool classPool = ClassPool.getDefault();
        private int totalCount = 0;
        //key: language, value: countries
        private Multimap<String, String>  localeMultiMap = ArrayListMultimap.create();
        private Map<String, Set<String>> langCountriesMap = new HashMap<>();
        private final String demoType;
        private final int loopCount;
    
        public OomDemo(String demoType, int loopCount) {
            this.demoType = demoType;
            this.loopCount = loopCount;
        }
    
        public void addLocale(String key, String value) {
    
            if(Strings.isBlank(key) || Strings.isBlank(value)) {
                return;
            }
            totalCount++;
            log.debug("addLocale {} -> {}", key, value);
            if("multimap".equals(demoType)) {
                this.localeMultiMap.put(key, value);
            } else {
                Set<String> countries = langCountriesMap.get(key);
                if(null == countries) {
                    countries = new HashSet<>();
                    langCountriesMap.put(key, countries);
                }
                countries.add(value);
            }
    
    
        }
        // java.lang.OutOfMemoryError:Java heap space
        public void noHeapSpace() {
            Integer[] array = new Integer[this.loopCount];
        }
    
        //java.lang.OutOfMemoryError: Metaspace or PermSpace
        public void noMetaSpace() throws CannotCompileException {
            for (int i = 0; i < this.loopCount; i++) {
                Class c = classPool.makeClass("com.github.walterfan.hellometrics.OomDemo" + i).toClass();
                log.info("{}. makeClass {}", i, c.getName());
            }
        }
    
    
        // java.lang.OutOfMemoryError: unable to create new native thread
        public void noNativeMemory() {
            for (int i = 0; i < this.loopCount; ++i) {
                new Thread() {
                    public void run() {
                        try {
                            Thread.sleep(1000000);
                        } catch(InterruptedException e) { }
                    }
                }.start();
                log.info("Thread " + i + " created");
            }
        }
    
    
        public void run() {
            log.info("--- run demo {} ---", this.demoType);
            try {
                switch (this.demoType) {
                    case "heap":
                        noHeapSpace();
                        break;
                    case "native":
                        noNativeMemory();
                        break;
                    case "meta":
                        noMetaSpace();
                        break;
                    default:
                        noHeapDemo();
    
                }
            } catch(Exception e) {
                log.error("run error of " + this.demoType + ", " + this.loopCount, e);
            }
        }
        // java.lang.OutOfMemoryError: Java heap space
        private void noHeapDemo() {
            for(long i =0; i < loopCount; ++i) {
                for(Locale locale: Locale.getAvailableLocales()) {
                    this.addLocale(locale.getLanguage(), locale.getCountry());
                    log.debug("{}/{}. {}", i, totalCount, locale);
                }
            }
            wait4Input(totalCount + " added, exit?");
            printLocales();
        }
    
        public static String wait4Input(String prompt) {
            System.out.print(prompt);
            System.out.flush();
    
            try (InputStreamReader is = new InputStreamReader(System.in)) {
                BufferedReader in = new BufferedReader(is);
                return in.readLine();
            } catch (IOException e) {
                System.err.println(e.getMessage());
            }
            return "";
        }
    
        public void printLocales() {
            final AtomicInteger i = new AtomicInteger(0);
    
            if("multimap".equals(demoType)) {
                localeMultiMap.keySet().stream().sorted().forEach(key -> {
                    log.info("{}. language: {}, countries: {} ", i.incrementAndGet(),
                            key,
                            localeMultiMap.get(key).stream().collect(Collectors.joining(",")));
                });
            } else {
    
                langCountriesMap.keySet().stream().sorted().forEach(key -> {
                    log.info("{}. language: {}, countries: {} ", i.incrementAndGet(),
                            key,
                            langCountriesMap.get(key).stream().collect(Collectors.joining(",")));
                });
            }
    
    
        }
    
        public static void launchTool(String type, String count)  {
            int loopCount = NumberUtils.toInt(count, 1);
            OomDemo demo = new OomDemo(type, loopCount);
            demo.run();
        }
    
        public static void main(String[] args) {
            Options options = new Options();
    
            Option opt = new Option("t", "type", true, "optional, sets the collection type: " +
                    "heap|native|meta|multimap|hashmap");
            options.addOption(opt);
    
            opt = new Option("c", "count", true, "optional, forever or loop number");
            options.addOption(opt);
    
            HelpFormatter hf = new HelpFormatter();
            hf.setWidth(110);
            CommandLine commandLine = null;
            CommandLineParser parser = new DefaultParser();
            try {
                commandLine = parser.parse(options, args);
                if (commandLine.hasOption('h')) {
                    hf.printHelp("helper", options, true);
                }
    
                launchTool(commandLine.getOptionValue("t"), commandLine.getOptionValue("c"));
    
            } catch (Exception e) {
                log.error("launch error: ", e);
                hf.printHelp("helper", options, true);
            }
    
        }
    
    }
    
    
    1. pom.xml
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.github.walterfan</groupId>
      <artifactId>hellometrics</artifactId>
      <packaging>jar</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>hellometrics</name>
      <url>http://maven.apache.org</url>
    
      <properties>
        <java.version>1.8</java.version>
        <dropwizard-metrics.version>3.1.0</dropwizard-metrics.version>
        <jackson.version>2.6.3</jackson.version>
        <guava.version>18.0</guava.version>
      </properties>
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
          <scope>test</scope>
        </dependency>
    
        <dependency>
          <groupId>io.dropwizard.metrics</groupId>
          <artifactId>metrics-httpclient</artifactId>
          <version>${dropwizard-metrics.version}</version>
        </dependency>
    
        <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>1.16.18</version>
          <scope>provided</scope>
        </dependency>
    
    
        <dependency>
          <groupId>com.google.guava</groupId>
          <artifactId>guava</artifactId>
          <version>${guava.version}</version>
        </dependency>
    
          <dependency>
              <groupId>commons-io</groupId>
              <artifactId>commons-io</artifactId>
              <version>2.6</version>
          </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
          <version>2.2.2.RELEASE</version>
        </dependency>
    
        <dependency>
          <groupId>commons-cli</groupId>
          <artifactId>commons-cli</artifactId>
          <version>1.4</version>
        </dependency>
    
        <dependency>
          <groupId>org.apache.commons</groupId>
          <artifactId>commons-lang3</artifactId>
          <version>3.9</version>
        </dependency>
    
        <dependency>
          <groupId>javassist</groupId>
          <artifactId>javassist</artifactId>
          <version>3.12.1.GA</version>
        </dependency>
      </dependencies>
    
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
              <source>1.8</source>
              <target>1.8</target>
            </configuration>
          </plugin>
    
          <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
              <archive>
                <manifest>
                  <mainClass>com.github.walterfan.hellometrics.OomDemo</mainClass>
                </manifest>
              </archive>
              <descriptorRefs>
                <descriptorRef>jar-with-dependencies</descriptorRef>
              </descriptorRefs>
            </configuration>
            <executions>
              <execution>
                <id>make-assembly</id> <!-- this is used for inheritance merges -->
                <phase>package</phase> <!-- bind to the packaging phase -->
                <goals>
                  <goal>single</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    </project>
    
    
    1. 运行脚本 run_oom_demo.sh
    HOME_PATH=.
    CLASS_PATH=./target/hellometrics-1.0-SNAPSHOT-jar-with-dependencies.jar
    MAIN_CLASS=com.github.walterfan.hellometrics.OomDemo
    startTime=$(date +%Y-%m-%d_%H_%M_%S)
    
    HEAP_OPTS="-Xms128m -Xmx256m -XX:MaxMetaspaceSize=64m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$HOME_PATH/heapdump_$startTime.hprof"
    
    GC_OPTS="-verbosegc -XX:+UseParallelGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+PrintGCDateStamps -Xloggc:./gc.log"
    
    JAVA_OPTS="-server $HEAP_OPTS $GC_OPTS -XX:StringTableSize=100003 -Dsun.net.inetaddr.ttl=15 -Djava.security.egd=file:/dev/./urandom -Duser.timezone=GMT -Dfile.encoding=UTF8"
    
    JMX_OPS="-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=8091 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.password.file=./jmxremote.password -Dcom.sun.management.jmxremote.access.file=./jmxremote.access"
    
    CMD_TYPE=multimap
    CMD_COUNT=100000000
    
    if [ $# -eq 1 ]
      then
        CMD_TYPE=$1
    fi
    if [ $# -eq 2 ]
      then
        CMD_TYPE=$1
        CMD_COUNT=$2
    fi
    
    APP_OPTS="-t $CMD_TYPE -c $CMD_COUNT"
    
    cmd="java $JAVA_OPTS $JMX_OPS -cp $CLASS_PATH $MAIN_CLASS $APP_OPTS"
    echo $cmd
    $cmd
    

    代码链接:https://github.com/walterfan/helloworld/tree/master/hellometrics

    参考资料

    相关文章

      网友评论

        本文标题:内存溢出不可怕,手足无措才尴尬

        本文链接:https://www.haomeiwen.com/subject/hnhhthtx.html