JVM调优(其一)

一、JVM简介

代码链接

1、为什么学习JVM

深入理解JVM可以帮助我们从平台角度提高解决问题以及优化系统的能力。

  • 1、有效防止内存泄偶,内存溢出;
  • 2、优化线程锁的使用;
  • 3、科学进行垃圾回收;
  • 4、提高系统吞吐量;
  • 5、降低延迟、提高其性能

2、JVM体系结构

2.1JVM的产品架构

JVM (Java HotSpot Architecture :主要分为三个部分:

  • 1、类加载系统:负责加载类到内存
  • 2、运行时数据区:负责存储数据信息
  • 3、执行引擎:负责调用对象执行业务

2.2JVM运行时内存结构是怎样的

JVM启动运行class文件时会对JVM内存进行切分,我们可以将其分为线程分享区合线程独享区。如下:
在这里插入图片描述
其运行时内存详细架构如下:
在这里插入图片描述
说明在JDK8中持久代数据迁移到了元数据区。

2.2.1JVM线程共享区应用分析
  • 1、Heap(堆内存)
    堆内存概要:
    1)虚拟机启动时创建,被所有线程共享,用于存放所有java对象实例。
    2)可分为年轻代和老年代。
    3)是垃圾回收器管理的主要区域。
    4)堆中没有内存分配时将会抛出OutOfMemoryError。
    对象内存分配说明:
    新创建的对象一般都分配在年轻代,当对象比较大时年轻代没有足够空间还可直接分配到老年代。有时候系统为了减少GC开销对于小对象且没有逃逸的对象还可以直接在栈上分配。
    堆内存大小配置参数说明:
    1)-Xms设置堆的最小空间大小。
    2)-Xmx设置堆的最大空间大小。
    3)-XX:NewSize设置新生代最小空间大小。
    4)-XX:MaxNewSize设置新生代最大空间大小。
    5)-XX:NewRatio新生代和老年代的比值,值为4则表示新生代:老年代1:4。
    6)-XX:SurivorRatio表示Survivor和Eden的比值,值为8表示两个幸存区survivor:eden=2:8。
    7)-Xss:设置每个线程的堆栈大小。
  • 2、Method Area(方法区)
    方法区概要:
    1)非堆内存,逻辑上的定义,用于存储类的数据结构信息。
    2)不同jdk,方法区的实现不同,JDK8中的方法去对应的是Metspace,是一块本地内存。
    方法存储说明:
    方法去内存配置参数说明:
    1)-XX:MetaspaceSize设置元数据区最小空间。
    2)-XX:MaxMetaspaceSize设置元数据区最大空间。
2.2.2JVM线程私有区应用分析
  • 1、Program Counter Register(程序计数器)
    1)线程启动时创建,线程私有。
    2)用于记录当前正在执行的虚拟机字节码指令地址。
    3)Java虚拟机规范唯一一个没有内存溢出的区域
  • 2、Stack Area(虚拟机栈区)
    虚拟机栈概要:
    1)用于存储栈帧(Satck Frame)对象,保存方法的局部变量表、操作数栈、执行运行时常量池的引用和一些额外的附加信息。
    2)一次方法调用都会创建一个新的栈帧,并压栈。当方法执行完毕之后,便会将栈帧出栈。
    3)栈上分配:对于小对象(一般几十个bytes),在没有逃逸的情况下,可以分配在栈上(直接分配在栈上,可以自动回收,减轻GC压力);大对象或者逃逸对象无法栈上分配。
    说明:方法在惊醒递归调用时容器出现栈内存溢出;
    虚拟机栈参数说明:
    1)-Xss128k:设置每个线程的堆栈大小
    JDK5.0以后每个线程堆栈大小为1m,以前每个线程堆栈大小为256k。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。
  • 3、Native Stack Area(本地方法栈)
    1)为虚拟机使用到的Native方法提供服务。
    2)用于存储本地方法执行时的一些变量信息,操作数信息,结果信息。

3、JVM应用参数分析

3.1如何理解JVM中的内存溢出?

每个java程序运行时都会使用一定量的内存,而jvm内存不足以满足当前java程序运行时所需要的内存资源时就会出现内存溢出的现象。
代码演示:堆内存溢出
在如下代码中假如不断的向list集合中存储新的对象,list集合底层也会不断的进行扩容,当内存中没有足够连续内存,空间存储这些对象时就会出现堆内存溢出。
代码:

import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args) {
        long t1 = System.currentTimeMillis();
        try {
            List<byte[]> list = new ArrayList<>();
            for (int i = 0;i<100;i++){
                list.add(new byte[1024*1024]);
            }
        }finally {
            long t2 = System.currentTimeMillis();
            System.out.println("oom"+(t2-t1));
        }
    }
}

参数:

-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump

结果:
在这里插入图片描述
代码演示:元数据内存溢出(JDK8)
当在有限的元数据内存区不断的加载新的类时会导致元数据区空间不足从而出现内存溢出的现象,例如:
代码:

package jvm;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * VM Args:-XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M(jdk8.0)
 */
public class TestCglibProxy {
    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(ProxyObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    System.out.println("i am proxy");
                    return methodProxy.invokeSuper(o, objects);
                }
            });
            ProxyObject proxy = (ProxyObject) enhancer.create();
            proxy.greet();
        }
    }

    static class ProxyObject{
        public String greet(){
            return "thanks gor you";
        }
    }
}

参数:

VM Args:-XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M(jdk8.0)

结果:
在这里插入图片描述

3.2JVM工具应用分析篇

3.2.1命令行工具篇
  • 1、Jps
    jps是用于查看有权访问的hotspot虚拟机的进程,当未指定hostid时,默认查看本机jvm进程。
-q	不输出类名、jar名和传入main方法的参数
-m	输出传入main方法的参数
-l	输出main类或jar的全限名
-v	输出传入jvm的参数

例如:
代码

public class TestCommand {
    public static void main(String[] args) {
        while (true){
            byte[] b1 = new byte[1024*1024];
        }
    }
}

执行:
1)Jps -l 输出应用程序朱磊完整package名称或jar完整名称
2)Jps -v 列出jvm参数

  • 2、jmap -heap pid
    用于打印指定java进程的对象内存映射或堆内存细节。
    代码:
public class TestCommand {
    public static void main(String[] args) {
        while (true){
            byte[] b1 = new byte[1024*1024];
        }
    }
}

例如获取如上代码的进程id之后,执行jmap -heap 24966可检测堆的配置信息,还可以借助jmap -histo:live 1963 快速定位内存泄漏
其中:
1)MaxHeapFreeRatio:最大空闲对内存比例,GC后如果发现空闲堆内存大于整个预估堆内存的N%(百分比),JVM则会收缩堆内存,但不能小于-Xms指定的最小堆的限制。
2)MinHeapFreeRatio:最小空闲对内存比例,GC后如果发现空闲堆内存小于整个预估堆内存的N%(百分比),则JVM会增大堆内存,但不能超过-Xms指定的最大限制
3)MaxHeapSize:即-Xmx,堆内存大小的上线
4)InitialHeapSize:即-Xms,堆内存大小的初始值
5)NewSize:新生代预估堆内存占用的默认值
6)MaxNewSize:新生代占整个堆内存的最大值
7)OldSize:老年代的默认大小
8)NewRatio:老年代对比新生代的空间大小,比如2代表老年代空间是新生代的两倍大小
9)SurvivorRatio:Eden/Survivor的值,例如8表示Survivor:Eden=1:8,因为survivor区有两个,所以Eden的占比未8/10.
10)MetaspaceSize:分配给元数据空间的初始大小(Oracle逻辑存储上的初始高水位,the initial high-water-mark)。此值为估计值,metaspaceSize设置的过大会延长垃圾回收时间。垃圾回收过后,引起下一次垃圾回收的类元数据空间的大小可能会变大
11)MaxMetaspaceSize:是分配给类元数据空间的最大值,超过此值就会触发Full GC,此值仅受限于系统内存的大小,jvm会动态的改变此值
12)CompressedClassSpaceSize:类指针压缩空间大小,默认为1G
13)G1HeapRegionSize:G1区块的大小,取值未1M至32M,其取值是要根据最小Heap大小划分出2048个区块。
说明:jmap在系统调优时通常会结合jhat来分析jmap生成的dump文件

  • 3、jstack用于生成java虚拟机当前时刻的线程快照
    生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。
    代码
package jvm;

import java.util.List;
import java.util.concurrent.TimeUnit;

public class SyncTack02 implements Runnable{
    private List<Integer> from;
    private List<Integer> to;
    private Integer target;

    public SyncTack02(List<Integer> from,List<Integer> to,Integer target){
        this.from=from;
        this.to=to;
        this.target=target;
    }

    @Override
    public void run() {
        moveListItem(from,to,target);
    }

    private static void moveListItem(List<Integer> from, List<Integer> to, Integer item) {
        log("attempting lock for list",from);
        synchronized (from){
            log("lock acquired for list",from);
            try{
                TimeUnit.SECONDS.sleep(1);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            log("attempting lock for list",to);
            synchronized (to){
                log("lock acquired for list",to);
                if (from.remove(item)){
                    to.add(item);
                }
                log("moved item to list",to);
            }
        }
    }

    private static void log(String msg, Object obj) {
        System.out.println(Thread.currentThread().getName()+":"+msg+""+System.identityHashCode(obj));
    }
}


package jvm;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class TestDeadLock02 {
    public static void main(String[] args) {
        List<Integer> list1 = new ArrayList<>(Arrays.asList(2,4,6,8,10));
        List<Integer> list2 = new ArrayList<>(Arrays.asList(1,3,5,7,9));

        Thread thread1 = new Thread(new SyncTack02(list1,list2,2));
        Thread thread2 = new Thread(new SyncTack02(list2,list1,9));

        thread1.start();
        thread2.start();
    }
}

执行 jstack -l 进程号,检测遇到的死锁问题

C:\Users\Maven’s PC>jps -l
22148 jvm.TestDeadLock02

C:\Users\Maven’s PC>jstack -l 22148
2021-01-19 14:58:00
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode):

"DestroyJavaVM" #14 prio=5 os_prio=0 tid=0x0000000003692800 nid=0x5d48 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Thread-1" #13 prio=5 os_prio=0 tid=0x000000001f269800 nid=0xc4d8 waiting for monitor entry [0x000000002006f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at jvm.SyncTack02.moveListItem(SyncTack02.java:33)
        - waiting to lock <0x000000076b6a0c30> (a java.util.ArrayList)
        - locked <0x000000076b6a1aa8> (a java.util.ArrayList)
        at jvm.SyncTack02.run(SyncTack02.java:19)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"Thread-0" #12 prio=5 os_prio=0 tid=0x000000001f269000 nid=0x3e60 waiting for monitor entry [0x000000001ff6f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at jvm.SyncTack02.moveListItem(SyncTack02.java:33)
        - waiting to lock <0x000000076b6a1aa8> (a java.util.ArrayList)
        - locked <0x000000076b6a0c30> (a java.util.ArrayList)
        at jvm.SyncTack02.run(SyncTack02.java:19)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - None

"Service Thread" #11 daemon prio=9 os_prio=0 tid=0x000000001f212000 nid=0x40b4 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C1 CompilerThread3" #10 daemon prio=9 os_prio=2 tid=0x000000001f1d4000 nid=0x766c waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x000000001f1bb000 nid=0x21b8 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x000000001f176800 nid=0x7c50 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x000000001f164000 nid=0xb1bc waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x000000001f140800 nid=0x8f1c runnable [0x000000001f86e000]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
        at java.net.SocketInputStream.read(SocketInputStream.java:171)
        at java.net.SocketInputStream.read(SocketInputStream.java:141)
        at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
        at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
        - locked <0x000000076b7cee10> (a java.io.InputStreamReader)
        at java.io.InputStreamReader.read(InputStreamReader.java:184)
        at java.io.BufferedReader.fill(BufferedReader.java:161)
        at java.io.BufferedReader.readLine(BufferedReader.java:324)
        - locked <0x000000076b7cee10> (a java.io.InputStreamReader)
        at java.io.BufferedReader.readLine(BufferedReader.java:389)
        at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:61)

   Locked ownable synchronizers:
        - None

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001f0a8000 nid=0x6678 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001f0a7000 nid=0x344c runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001f090800 nid=0xa530 in Object.wait() [0x000000001f56e000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076b508ec8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
        - locked <0x000000076b508ec8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

   Locked ownable synchronizers:
        - None

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000003789000 nid=0x6f2c in Object.wait() [0x000000001f06e000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x000000076b506b68> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
        - locked <0x000000076b506b68> (a java.lang.ref.Reference$Lock)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

   Locked ownable synchronizers:
        - None

"VM Thread" os_prio=2 tid=0x000000001d199000 nid=0x8f80 runnable

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000036a8000 nid=0xa014 runnable

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000036a9800 nid=0x42f8 runnable

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00000000036ab000 nid=0x6824 runnable

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00000000036ae000 nid=0xab0c runnable

"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00000000036b0000 nid=0x8fd0 runnable

"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00000000036b1000 nid=0x8484 runnable

"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x00000000036b4800 nid=0x806c runnable

"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x00000000036b5800 nid=0xc66c runnable

"VM Periodic Task Thread" os_prio=2 tid=0x000000001f262000 nid=0x7c98 waiting on condition

JNI global references: 33


Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x000000001d1a0e98 (object 0x000000076b6a0c30, a java.util.ArrayList),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x000000001d1a35c8 (object 0x000000076b6a1aa8, a java.util.ArrayList),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
        at jvm.SyncTack02.moveListItem(SyncTack02.java:33)
        - waiting to lock <0x000000076b6a0c30> (a java.util.ArrayList)
        - locked <0x000000076b6a1aa8> (a java.util.ArrayList)
        at jvm.SyncTack02.run(SyncTack02.java:19)
        at java.lang.Thread.run(Thread.java:748)
"Thread-0":
        at jvm.SyncTack02.moveListItem(SyncTack02.java:33)
        - waiting to lock <0x000000076b6a1aa8> (a java.util.ArrayList)
        - locked <0x000000076b6a0c30> (a java.util.ArrayList)
        at jvm.SyncTack02.run(SyncTack02.java:19)
        at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.


C:\Users\Maven’s PC>
3.3.2GUI工具篇

1)Jconsole(Jdk自带)
JConsole是一个内置Java性能分析器,可以从命令行(直接输入jconsole)或在GUI shell(jdk\bin下打开)中运行,它用于对JVM中内存,线程和类等的监控。它可以监控本地的jvm,也可以监控远程的jvm,也可以同时监控几个jvm。
这块工具的好处在于,占用系统资源少,而且结合Jstat,可以有效监控到java内存的变动情况,以及引起变动的原因。在项目追踪内存泄漏问题时,很实用
在这里插入图片描述
在这里插入图片描述
2)VisualVM
是一种集成了多个JDK命令行工具的可视化工具,它可以为您提供强大的分析能力,在VisualVM的图形用户界面中,您可以方便/快捷的查看多个java应用程序的相关信息。
3)基于MAT分析
Memory Analoyzer Tool(MAT)一个强大的基于内存的分析工具,可以帮助我们找到内存泄漏,减少内存消耗。

4、JVM实践应用分析

4.1对象内存分配及日志分析

程序中大部分新创建的对象会分配在年轻代内存,例如有如下代码:
代码:

package jvm;

public class TestMemory01 {
    public static void main(String[] args) {
        byte[] b1 = new byte[1024*1024];//分配1MB空间,考察堆空间的使用情况
        byte[] b2 = new byte[1024*1024];
        byte[] b3 = new byte[1024*1024];
        byte[] b4 = new byte[1024*1024];
    }
}

配置参数:

-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xmx1G -Xms1G -Xmn500M

结果:

Heap
 PSYoungGen      total 448000K, used 30720K [0x00000000e0c00000, 0x0000000100000000, 0x0000000100000000)
  eden space 384000K, 8% used [0x00000000e0c00000,0x00000000e2a001b8,0x00000000f8300000)
  from space 64000K, 0% used [0x00000000fc180000,0x00000000fc180000,0x0000000100000000)
  to   space 64000K, 0% used [0x00000000f8300000,0x00000000f8300000,0x00000000fc180000)
 ParOldGen       total 6144K, used 0K [0x00000000c0000000, 0x00000000c0600000, 0x00000000e0c00000)
  object space 6144K, 0% used [0x00000000c0000000,0x00000000c0000000,0x00000000c0600000)
 Metaspace       used 3498K, capacity 4498K, committed 4864K, reserved 1056768K
  class space    used 387K, capacity 390K, committed 512K, reserved 1048576K

Process finished with exit code 0

结果分析:
1)整个运行过程没有出发GC操作
2)对象都被分配在了年轻代的伊甸园区
配置相同内存,运行参数设置为:

-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xmx20M -Xmx20M -Xmn4M

结果:

0.315: [GC (Allocation Failure) [PSYoungGen: 3072K->488K(3584K)] 3072K->1768K(19968K), 0.0334910 secs] [Times: user=0.00 sys=0.00, real=0.03 secs] 
0.349: [GC (Allocation Failure) [PSYoungGen: 2626K->488K(3584K)] 3906K->3816K(19968K), 0.0024175 secs] [Times: user=0.02 sys=0.02, real=0.00 secs] 
Heap
 PSYoungGen      total 3584K, used 1564K [0x00000000ffc00000, 0x0000000100000000, 0x0000000100000000)
  eden space 3072K, 35% used [0x00000000ffc00000,0x00000000ffd0d2d0,0x00000000fff00000)
  from space 512K, 95% used [0x00000000fff80000,0x00000000ffffa020,0x0000000100000000)
  to   space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
 ParOldGen       total 16384K, used 3328K [0x00000000fec00000, 0x00000000ffc00000, 0x00000000ffc00000)
  object space 16384K, 20% used [0x00000000fec00000,0x00000000fef40030,0x00000000ffc00000)
 Metaspace       used 3482K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 385K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 0

结果分析:
JVM启动之后315ms,共创建了3072K KB的对象。第一次Minor GC(小型GC)完成后,年轻代中还有488K的对象存货,括号中的3584表示新生代总大小,3072表示GC前堆大小,1768表示GC后堆大小,括号中的19968为堆总大小。0.0334910 secs表示GC时间。

4.2Tomcat中内存配置应用分析

tomcat一般都有默认的内存大小,其默认值对整个物理内存来说非常小,如果不配置tomcat的内存,会大大浪费服务器的资源,严重影响系统的性能,所以tomcat的内存配置对用户量比较大的系统来说尤为重要。
windows平台下在bin目录下的catalina.bat文件中,找到@echo off 然后在它的下面一行添加如下类似语句。

参数设置:

SET CATALINA_OPTS = -Xms8192m -Xmx8192m -Xmn1890m

参数说明:

-server:一定要作为第一个参数,在多个cpu时性能佳
-Xms:java Heap初始大小。默认是物理内存的1/64.
-Xmx:java heap的最大值,建议均设为物理内存的一般。不可超过物理内存
-Xmn:young generation(年轻代)的heap大小,一般为Xmx的3、4分之一
-XX:MetaSpaceSize=128m初始元空间大小,默认一般为21m。
-XX:MaxMetaSpaceSize=256m最大元空间大小。默认无上限,由os内存决定

下一篇:JVM调优(其二)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值