分享

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

 vnxy001 2021-12-14

内存溢出错误简称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./POM/4.0.0" xmlns:xsi="http://www./2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven./POM/4.0.0 http://maven./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.</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

参考资料

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多