原创 

学习笔记之JVM OOM内存溢出模拟及JVM打印日志分析(环境win10)

分类:java    707人阅读    IT小君  2021-06-09 13:23

1、首先准备一份代码

package com.icode;

import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;

import java.io.OutputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;

/**
 * 模拟JVM内存溢出
 * 原理: 开放了一个 HTTP 接口,当请求之后,将每秒钟生成 1MB 的数据。由于它和 GC Roots 的强关联性,每次都不能被回收。
 */
public class OOMTest {

    public static final int _1MB = 1024 * 1024;
    static List<byte[]> byteList = new ArrayList<>();// 放在堆里
    private static void oom(HttpExchange exchange) {
        try {
            String response = "oom begin!";
            exchange.sendResponseHeaders(200, response.getBytes().length);
            OutputStream os = exchange.getResponseBody();
            os.write(response.getBytes());
            os.close();
        } catch (Exception ex) {
        }
        for (int i = 0; ; i++) {
            byte[] bytes = new byte[_1MB];
            byteList.add(bytes);
            System.out.println(i + "MB");
            memPrint();
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
            }
        }
    }
    static void memPrint() {
        for (MemoryPoolMXBean memoryPoolMXBean : ManagementFactory.getMemoryPoolMXBeans()) {
            System.out.println(memoryPoolMXBean.getName() +
                    "  committed:" + memoryPoolMXBean.getUsage().getCommitted() +
                    "  used:" + memoryPoolMXBean.getUsage().getUsed());
        }
    }
    private static void srv() throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8888), 0);
        HttpContext context = server.createContext("/");
        context.setHandler(OOMTest::oom);
        server.start();
    }
    public static void main(String[] args) throws Exception{
        srv();
    }

}

以上代码注释中什么是GC Roots?

GC Roots一般都是些堆外指向堆内的引用,例如:

  1. JVM栈中引用的对象
  2. 方法区中静态属性引用的对象
  3. 方法区中常量引用的对象
  4. 本地方法栈中引用的对象 

2、编译,使用JAVA命令运行字节码文件

F:\cmder_mini
λ E:

E:\
λ cd E:\procedure\java\JVMDemo

E:\procedure\java\JVMDemo
λ java -classpath ".\target\classes" -Xmx20m -Xmn4m -XX:+UseConcMarkSweepGC -verbose:gc -XX:+PrintGCDetails -Xloggc:".\gclog.log" com.icode.OOMTest

参数解释:

-Xmx 最大堆大小  

-Xmn 年轻代大小

-XX:+UseConcMarkSweepGC  使用CMS内存收集

-verbose:gc //在控制台输出GC情况 

-XX:+PrintGCDetails //在控制台输出详细的GC情况 

-Xloggc: filepath //将GC日志输出到指定文件中

先把-Xloggc去掉我们直接打印到控制台


输入如下信息:

[GC (Allocation Failure) [ParNew: 3328K->384K(3712K), 0.0114718 secs] 3328K->1132K(20096K), 0.0158854 secs] [Times: user=0.13 sys=0.00, real=0.02 secs]

日志解析:

GC: 表明进行了一次垃圾回收,前面没有Full修饰,表明这是一次Minor GC 

 Allocation Failure: 表明本次引起GC的原因是因为在年轻代中没有足够的空间能够存储新的数据了。 

ParNew:表明本次GC发生在年轻代并且使用的是ParNew垃圾收集器。ParNew是一个Serial收集器的多线程版本,会使用多个CPU和线程完成垃圾收集工作(默认使用的线程数和CPU数相同,可以使用-XX:ParallelGCThreads参数限制)。该收集器采用复制算法回收内存,期间会停止其他工作线程,即Stop The World。

3328K->384K(3712K):单位是KB 三个参数分别为:GC前该内存区块使用容量,GC后该内存区块使用容量,该内存区域总容量。 

0.0114718 secs: 该内存区块GC耗时,单位是秒

3328K->1132K(20096K): 三个参数分别为:堆区垃圾回收前的大小,堆区垃圾回收后的大小,堆区总大小。 

.0158854 secs: 该内存区域GC耗时,单位是秒 

[Times: user=0.13 sys=0.00, real=0.02 secs]:     分别表示用户态耗时,内核态耗时和总耗时,一般用户只关心总耗时

 

由上可知:老年代占用内存为 1132K-384K=748K

点击广告,支持我们为你提供更好的服务

HTML5现代家居装潢公司网站模板

网页设计开发公司网站模板

中小型创意设计服务公司网站模板

html5 canvas进度条圆环图表统计动画特效

现代时尚家具公司网站模板

css+js实现的颜色渐变数字时钟动画特效

响应式咖啡饮品宣传网站模板

小众时尚单品在线电子商务网站模板

响应式时尚单品在线商城网站模板

css鼠标跟随文字模糊特效

HTML5数字产品服务公司网站模板

html5图标下拉搜索框自动匹配代码

canvas炫酷鼠标移动文字粒子特效

有机水果蔬菜HTML5网站模板

HTML5 Canvas竖直流动线条背景动画特效

js+css3抽奖转盘旋转点餐代码

html5 canvas彩色碎片组合球形旋转动画特效

html5 svg夜空中星星流星动画场景特效

jQuery右端悬浮带返回顶部特效

响应式太阳能能源公司网站模板

点击广告,支持我们为你提供更好的服务
 工具推荐 更多»
点击广告,支持我们为你提供更好的服务