JVM内存调优学习记录

JVM 内存调优

JVM 内存调优学习记录

堆内存中分配两个区: 新生代, 老年代

新生代(PSYoungGen): 创建对象,先存放在新生代

新生代包含: eden、from、to

老年代(ParOldGen):如果对象频繁的使用,对象放入到老年代

对象进入老年代后,如果不再频繁使用了,不会回到新生代

当内存空间紧张时会触发 Full GC 对老年代空间进行垃圾回收,针对老年代空间进行GC操作.

JVM 参数调优
  • 堆内存初始值与堆内存最大值一定要保持一致(原因: 减少垃圾回收机制次数)
参数配置
参数描述
-XX:+PrintGC每次触发GC的时候打印相关日志
-XX:+UseSerialGC串行回收
-XX:+PrintGCDetails更详细的GC日志
-Xms堆初始值
-Xmx堆最大可用值
-Xmn新生代堆最大可用值
-XX:SurvivorRatio用来设置新生代中eden空间和from/to空间的比例.
-XX:NewRatio设置新生代和老年代内存比例
-Xss设置每个线程的堆栈大小
栈内存溢出示例

描述

栈溢出主要是因为递归调用到达了零界点 ,导致系统内存移除.

解决方法
# 添加vm arg 参数
# 调整深度
-Xss 10m
  • 栈内存溢出代码示例
public class Main {

    private static int count = 0;

    public static void getCount() {
        try {
            count++;
            getCount();
        } catch (Throwable e) {
            System.err.println("递归次数: " + count);
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        getCount();
    }
}

错误信息

递归次数: 17794
java.lang.StackOverflowError
...(以下错误信息省略)
  • 设置 JVM 参数: -Xss10m

错误信息

通过修改 JVM 参数 -Xss 后, 递归调用的次数明显增多.

递归次数: 614518
java.lang.StackOverflowError
...(以下错误信息省略)
堆内存参数配置

最小堆内存5M 最大堆内存. 最终 GC 两次

-XX:+PrintGCDetails 打印详细的 GC 信息

-Xms5m -Xmx20m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+PrintCommandLineFlags

测试一
  • 设置堆的初始值为 5m, 最大值为 20m -Xms5m -Xmx20m.
# JVM 参数配置
-Xms5m -Xmx20m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+PrintCommandLineFlags
  • 示例代码
public static void main(String[] args) throws InterruptedException {

    byte[] me = new byte[1 * 1024 *1024];
    System.out.println("分配了 1M 内存");
    byte[] byte02 = new byte[4 * 1024 *1024];
    System.out.println("分配了 4M 内存");
}
  • 执行结果

设置堆的初始值为 5m, 最大值为 20m. 此时垃圾回收机制回收了两次

-XX:InitialHeapSize=5242880 -XX:MaxHeapSize=20971520 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseSerialGC 
Connected to the target VM, address: '127.0.0.1:58563', transport: 'socket'
[GC (Allocation Failure) [DefNew: 1141K->192K(1856K), 0.0023176 secs] 1141K->716K(5952K), 0.0023745 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
分配了 1M 内存
[GC (Allocation Failure) [DefNew: 1247K->0K(1856K), 0.0016138 secs][Tenured: 1740K->1740K(4096K), 0.0021735 secs] 1771K->1740K(5952K), [Metaspace: 2908K->2908K(1056768K)], 0.0038473 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
分配了 4M 内存
[GC (Allocation Failure) [DefNew: 32K->0K(1920K), 0.0003316 secs][Tenured: 5836K->5836K(8196K), 0.0034514 secs] 5869K->5836K(10116K), [Metaspace: 2908K->2908K(1056768K)], 0.0039188 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Disconnected from the target VM, address: '127.0.0.1:58563', transport: 'socket'
分配了 4M 内存
Heap
 def new generation   total 4480K, used 81K [0x00000000fec00000, 0x00000000ff0d0000, 0x00000000ff2a0000)
  eden space 4032K,   2% used [0x00000000fec00000, 0x00000000fec14468, 0x00000000feff0000)
  from space 448K,   0% used [0x00000000feff0000, 0x00000000feff0000, 0x00000000ff060000)
  to   space 448K,   0% used [0x00000000ff060000, 0x00000000ff060000, 0x00000000ff0d0000)
 tenured generation   total 13696K, used 10956K [0x00000000ff2a0000, 0x0000000100000000, 0x0000000100000000)
   the space 13696K,  80% used [0x00000000ff2a0000, 0x00000000ffd533d0, 0x00000000ffd53400, 0x0000000100000000)
 Metaspace       used 2915K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 310K, capacity 386K, committed 512K, reserved 1048576K
测试二
  • 设置堆的初始值为 5m, 最大值为 20m -Xms5m -Xmx20m.
# JVM 参数配置
-Xms20m -Xmx20m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:+PrintCommandLineFlags
  • 示例代码
public static void main(String[] args) throws InterruptedException {

    byte[] me = new byte[1 * 1024 *1024];
    System.out.println("分配了 1M 内存");
    byte[] byte02 = new byte[4 * 1024 *1024];
    System.out.println("分配了 4M 内存");
}
  • 执行结果

设置堆的初始值为 20m, 最大值为 20m. 此时垃圾回收机制回收了一次

# 初始值与最大值一致, 最终 GC 一次
-XX:InitialHeapSize=20971520 -XX:MaxHeapSize=20971520 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseSerialGC 
Connected to the target VM, address: '127.0.0.1:58637', transport: 'socket'
分配了 1M 内存
[GC (Allocation Failure) [DefNew: 2460K->640K(6144K), 0.0031363 secs] 2460K->1740K(19840K), 0.0032275 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
分配了 4M 内存
Disconnected from the target VM, address: '127.0.0.1:58637', transport: 'socket'
Heap
 def new generation   total 6144K, used 4883K [0x00000000fec00000, 0x00000000ff2a0000, 0x00000000ff2a0000)
  eden space 5504K,  77% used [0x00000000fec00000, 0x00000000ff024cb0, 0x00000000ff160000)
  from space 640K, 100% used [0x00000000ff200000, 0x00000000ff2a0000, 0x00000000ff2a0000)
  to   space 640K,   0% used [0x00000000ff160000, 0x00000000ff160000, 0x00000000ff200000)
 tenured generation   total 13696K, used 1100K [0x00000000ff2a0000, 0x0000000100000000, 0x0000000100000000)
   the space 13696K,   8% used [0x00000000ff2a0000, 0x00000000ff3b3320, 0x00000000ff3b3400, 0x0000000100000000)
 Metaspace       used 2919K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 310K, capacity 386K, committed 512K, reserved 1048576K
结论

堆内存初始值与堆内存最大值保持一致可减少垃圾回收机制次数

新生代空间分配
  • JVM 配置
# -Xmn1m 设置新生代内存为1m
# -XX:SurvivorRatio=2 设置 eden 区和 from/to 空间的比例 (from/to 为 eden区的二分之一)
-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
  • 示例代码
public static void main(String[] args) {
    for (int i = 0; i < 10; i++) {
        // 创建 1 M 空间
        byte = new byte[1 * 1024 * 1024];
    }
}
  • GC 信息
##################### 运行堆内存信息  ###############################
eden 为 512K 
from|to 为 256K 占 eden 区的二分一
###################################################################
Heap
 def new generation   total 768K, used 281K [0x00000000fec00000, 0x00000000fed00000, 0x00000000fed00000)
  eden space 512K,   5% used [0x00000000fec00000, 0x00000000fec06720, 0x00000000fec80000)
  from space 256K,  99% used [0x00000000fec80000, 0x00000000fecbfff8, 0x00000000fecc0000)
  to   space 256K,   0% used [0x00000000fecc0000, 0x00000000fecc0000, 0x00000000fed00000)
 tenured generation   total 19456K, used 10693K [0x00000000fed00000, 0x0000000100000000, 0x0000000100000000)
   the space 19456K,  54% used [0x00000000fed00000, 0x00000000ff771428, 0x00000000ff771600, 0x0000000100000000)
 Metaspace       used 2908K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 309K, capacity 386K, committed 512K, reserved 1048576K
设置新生代和老年代参数
  • JVM 配置
# XX:NewRatio=2 设置新生代和老年代的比例(XX:NewRatio=2: 老年代空间是新生代空间的两倍)
-Xms20m -Xmx20m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC -XX:NewRatio=2
  • 示例代码
public static void main(String[] args) {
    for (int i = 0; i < 10; i++) {
        // 创建 1 M 空间
        byte = new byte[1 * 1024 * 1024];
    }
}
  • GC 信息
##################### 运行堆内存信息  ###############################
eden + from + to = 6784K
the space 13696K
新生代区 * 2 约等于老年代
###################################################################

Heap
 def new generation   total 5120K, used 3169K [0x00000000fec00000, 0x00000000ff2a0000, 0x00000000ff2a0000)
  eden space 3456K,  62% used [0x00000000fec00000, 0x00000000fee18458, 0x00000000fef60000)
  from space 1664K,  61% used [0x00000000ff100000, 0x00000000ff200010, 0x00000000ff2a0000)
  to   space 1664K,   0% used [0x00000000fef60000, 0x00000000fef60000, 0x00000000ff100000)
 tenured generation   total 13696K, used 715K [0x00000000ff2a0000, 0x0000000100000000, 0x0000000100000000)
   the space 13696K,   5% used [0x00000000ff2a0000, 0x00000000ff352e08, 0x00000000ff353000, 0x0000000100000000)
 Metaspace       used 2907K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 309K, capacity 386K, committed 512K, reserved 1048576K
堆内存溢出

堆内存溢出的主要体现为老年代和新生代的使用空间不足.无法分配足够的内存空间.

解决方案:

# 修改堆的初始值和最大值.
-Xms512m -Xmx512m
堆内存溢出示例
  • JVM 配置

假设将 JVM 的初始内存和最大内存设置为 5

-Xms5m -Xmx5m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDetails
  • 对堆内存溢出示例代码
public static void main(String[] args) {
    List<Object> list = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        System.out.println("i:" + i);
        // 申请 10M 的空间
        list.add(new byte[1 * 1024 * 1024]);
    }
    System.out.println("添加完成...");
}
  • 结果

Full GC 表示触发了老年代的 GC 操作

代码执行后提示内存溢出错误.java.lang.OutOfMemoryError: Java heap space

原因: JVM 的最大内存只有 5m, 但是程序创建了10m空间.JVM无法创建10m内存,内存使用不足,最后导致内存溢出.

Connected to the target VM, address: '127.0.0.1:58799', transport: 'socket'
[GC (Allocation Failure) [PSYoungGen: 1018K->488K(1536K)] 1018K->736K(5632K), 0.0012770 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
i:0
i:1
i:2
i:3
[GC (Allocation Failure) [PSYoungGen: 562K->504K(1536K)] 3883K->3848K(5632K), 0.0009257 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 504K->480K(1536K)] 3848K->3916K(5632K), 0.0005384 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 480K->0K(1536K)] [ParOldGen: 3436K->3787K(4096K)] 3916K->3787K(5632K), [Metaspace: 2912K->2912K(1056768K)], 0.0082153 secs] [Times: user=0.05 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 3787K->3787K(5632K), 0.0004224 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] [ParOldGen: 3787K->3763K(4096K)] 3787K->3763K(5632K), [Metaspace: 2912K->2912K(1056768K)], 0.0083167 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid15116.hprof ...
Heap dump file created [4601798 bytes in 0.015 secs]
Disconnected from the target VM, address: '127.0.0.1:58799', transport: 'socket'
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.xcc.jvm.Demo04.main(Demo04.java:22)
Heap
 PSYoungGen      total 1536K, used 30K [0x00000000ffe00000, 0x0000000100000000, 0x0000000100000000)
  eden space 1024K, 2% used [0x00000000ffe00000,0x00000000ffe078f0,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
  to   space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
 ParOldGen       total 4096K, used 3763K [0x00000000ffa00000, 0x00000000ffe00000, 0x00000000ffe00000)
  object space 4096K, 91% used [0x00000000ffa00000,0x00000000ffdacee8,0x00000000ffe00000)
 Metaspace       used 2943K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 312K, capacity 386K, committed 512K, reserved 1048576K
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值