JVM之JVM虚拟机参数配置

生活中,最使人疲惫的往往不是道路的遥远,而是心中的郁闷;最使人痛苦的往往不是生活的不幸,而是希望的破灭;最使人颓废的往往不是前途的坎坷,而是自信的丧失;最使人绝望的往往不是挫折的打击,而是心灵的死亡。所以我们要有自己的梦想,让梦想的星光指引着我们走出落漠,走出惆怅,带着我们走进自己的理想。

导读:本篇文章讲解 JVM之JVM虚拟机参数配置,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

JVM参数

JVM参数类型分为三类:

标准参数

-X参数 (非标准参数)

-XX参数(使用率较高)

标准参数

jvm的标准参数,一般很稳定,在未来JVM版本中不会改变,可以使用java -help检索出所有的标准参数

D:\>java -help
用法: java [-options] class [args...]
           (执行类)
   或  java [-options] -jar jarfile [args...]
           (执行 jar 文件)
其中选项包括:
    -d32          使用 32 位数据模型 (如果可用)
    -d64          使用 64 位数据模型 (如果可用)
    -server       选择 "server" VM
                  默认 VM 是 server.

    -cp <目录和 zip/jar 文件的类搜索路径>
    -classpath <目录和 zip/jar 文件的类搜索路径>; 分隔的目录, JAR 档案
                  和 ZIP 档案列表, 用于搜索类文件。
    -D<名称>=<>
                  设置系统属性
    -verbose:[class|gc|jni]
                  启用详细输出
    -version      输出产品版本并退出
    -version:<>
                  警告: 此功能已过时, 将在
                  未来发行版中删除。
                  需要指定的版本才能运行
    -showversion  输出产品版本并继续
    -jre-restrict-search | -no-jre-restrict-search
                  警告: 此功能已过时, 将在
                  未来发行版中删除。
                  在版本搜索中包括/排除用户专用 JRE
    -? -help      输出此帮助消息
    -X            输出非标准选项的帮助
    -ea[:<packagename>...|:<classname>]
    -enableassertions[:<packagename>...|:<classname>]
                  按指定的粒度启用断言
    -da[:<packagename>...|:<classname>]
    -disableassertions[:<packagename>...|:<classname>]
                  禁用具有指定粒度的断言
    -esa | -enablesystemassertions
                  启用系统断言
    -dsa | -disablesystemassertions
                  禁用系统断言
    -agentlib:<libname>[=<选项>]
                  加载本机代理库 <libname>, 例如 -agentlib:hprof
                  另请参阅 -agentlib:jdwp=help 和 -agentlib:hprof=help
    -agentpath:<pathname>[=<选项>]
                  按完整路径名加载本机代理库
    -javaagent:<jarpath>[=<选项>]
                  加载 Java 编程语言代理, 请参阅 java.lang.instrument
    -splash:<imagepath>
                  使用指定的图像显示启动屏幕
有关详细信息, 请参阅 http://www.oracle.com/technetwork/java/javase/documentation/index.html。

设置运行JVM参数测试

1.程序代码如下

public class Test {
    public static void main(String[] args) {
        String test = System.getProperty("test");
        System.out.println("test: " + test);
    }
}

2.在运行时指定JVM参数,使用-D参数名=值的形式,在spring boot中使用较多
在这里插入图片描述

已连接到目标 VM, 地址: ''127.0.0.1:6164',传输: '套接字''
test: Ok
与目标 VM 断开连接, 地址为: ''127.0.0.1:6164',传输: '套接字''

-X参数

jvm的-X参数是非标准参数,意味着在不同的jvm版本中,参数可能会变动,可以通过java -X查看非标准参数。

D:\>java -X
    -Xmixed           混合模式执行(默认)
    -Xint             仅解释模式执行
    -Xbootclasspath:<; 分隔的目录和 zip/jar 文件>
                      设置引导类和资源的搜索路径
    -Xbootclasspath/a:<; 分隔的目录和 zip/jar 文件>
                      附加在引导类路径末尾
    -Xbootclasspath/p:<; 分隔的目录和 zip/jar 文件>
                      置于引导类路径之前
    -Xdiag            显示附加诊断消息
    -Xnoclassgc        禁用类垃圾收集
    -Xincgc           启用增量垃圾收集
    -Xloggc:<file>    将 GC 状态记录在文件中(带时间戳)
    -Xbatch           禁用后台编译
    -Xms<size>        设置初始 Java 堆大小
    -Xmx<size>        设置最大 Java 堆大小
    -Xss<size>        设置 Java 线程堆栈大小
    -Xprof            输出 cpu 分析数据
    -Xfuture          启用最严格的检查,预计会成为将来的默认值
    -Xrs              减少 Java/VM 对操作系统信号的使用(请参阅文档)
    -Xcheck:jni       对 JNI 函数执行其他检查
    -Xshare:off       不尝试使用共享类数据
    -Xshare:auto      在可能的情况下使用共享类数据(默认)
    -Xshare:on        要求使用共享类数据,否则将失败。
    -XshowSettings    显示所有设置并继续
    -XshowSettings:system
                      (仅限 Linux)显示系统或容器
                      配置并继续
    -XshowSettings:all
                      显示所有设置并继续
    -XshowSettings:vm 显示所有与 vm 相关的设置并继续
    -XshowSettings:properties
                      显示所有属性设置并继续
    -XshowSettings:locale
                      显示所有与区域设置相关的设置并继续

-X 选项是非标准选项。如有更改,恕不另行通知。

-XX参数

-XX参数也是非标准参数,数是使用得最多的参数,主要用于JVM调优和Debug操作。

-XX参数的使用方式:

一种是boolean类型

一种是非boolean类型

Boolean类型

格式:-XX:[+-]<name> +-表示启用或者禁用name属性

-XX:+UseConcMarkSweepGC 表示启用CMS类型的垃圾回收器

-XX:+UseG1GC 表示启用G1类型的垃圾回收器

-XX:+DisableExplicitGC 表示禁用手动调用gc操作,调用System.gc()无效

非Boolean类型

格式:-XX:<name>=<value>表示name属性的值是value

-XX:MaxGCPauseMillis=500 表示每次GC最大的停顿毫秒数

-XX:GCTimeRatio=nnn 表示希望在GC花费不超过应用程序执行时间的1/(1+nnn),nnn为大于0小于100的整数。

-XX:NewRatio=1 表示新生代和老年代的比值

运行参数

运行java命令时打印参数

运行java命令时打印参数,添加 -XX:+PrintFlagsFinall参数即可

java -XX:+PrintFlagsFinal

查看正在运行的jvm参数

如果想要查看正在运行的jvm就需要借助于jinfo命令查看

通过jps命令或者jps ‐l命令查看java进程

[root@administrator ~]# jps
57797 Jps
1320 Application
18876 Bootstrap

[root@administrator ~]# jps -l
1320 com.aliyun.tianji.cloudmonitor.Application
57865 sun.tools.jps.Jps
18876 org.apache.catalina.startup.Bootstrap

查看所有的参数:jinfo ‐flags 进程id

[root@administrator ~]# jinfo -flags 1320
Attaching to process ID 1320, please wait...

查看某一参数的值:jinfo ‐flag 参数名 进程id

[root@administrator ~]# jinfo  -flags MaxHeapSize 1320
Attaching to core 1320 from executable MaxHeapSize, please wait...

将运行JVM参数写入某路径某文件

java -XX:+PrintFlagsFinal > flagsFinal.txt

参数有boolean类型和数字类型,值的操作符是=或:=,分别代表默认值和被修改的值

在这里插入代码片

JVM参数配置

虚拟机提供了一些跟踪系统状态的参数,使用给定的参数执行Java虚拟机,就可以在系统运行时打印相关日志,用于分析实际问题。进行虚拟机参数配置,其实就是围绕着堆、栈、方法区、进行配置。

堆的参数配置

-XX:+PrintGC      每次触发GC的时候打印相关日志

-XX:+UseSerialGC      串行回收

-XX:+PrintGCDetails  更详细的GC日志

-Xms               堆初始值

-Xmx               堆最大可用值

-Xmn               新生代堆最大可用值

-XX:SurvivorRatioo=eden/from=den/to     用来设置新生代中eden空间和from/to空间的比例 

-XX:NewRatio=老年代/新生代    设置新生代和老年代的比例

设置最大堆内存

-Xms5m -Xmx20m -XX:+PrintGCDetails -XX:+UseSerialGC
	public static void main(String[] args) throws InterruptedException {
		byte[] bytes1 = new byte[1 * 1024 * 1024];
		System.out.println("分配1m");
		pintJvmInfo();
		Thread.sleep(3000);
		byte[] bytes2 = new byte[4 * 1024 * 1024];
		System.out.println("分配4m");
		Thread.sleep(3000);
		pintJvmInfo();

	}
	
	static private void pintJvmInfo() {
		// 最大内存
		long maxMemory = Runtime.getRuntime().maxMemory();
		System.out.println("最大内存:" + maxMemory);
		// 当前空闲内存
		long freeMemory = Runtime.getRuntime().freeMemory();
		System.out.println("当前空闲内存:" +freeMemory);
		// 已使用内存
		long totalMemory = Runtime.getRuntime().totalMemory();
		System.out.println("已使用内存:" +totalMemory);
	}
[GC (Allocation Failure) [DefNew: 1580K->192K(1856K), 0.0060484 secs] 1580K->590K(5952K), 0.0062694 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
分配1m
最大内存:20316160
当前空闲内存:4391080
已使用内存:6094848
[GC (Allocation Failure) [DefNew: 1856K->192K(1856K), 0.0020850 secs] 2254K->1876K(5952K), 0.0021337 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [DefNew: 619K->138K(1856K), 0.0007739 secs][Tenured: 1858K->1996K(4096K), 0.0021105 secs] 2303K->1996K(5952K), [Metaspace: 3800K->3800K(1056768K)], 0.0029790 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
分配4m
最大内存:20316160
当前空闲内存:4090896
已使用内存:10358784
Heap
 def new generation   total 1920K, used 45K [0x00000000fec00000, 0x00000000fee10000, 0x00000000ff2a0000)
  eden space 1728K,   2% used [0x00000000fec00000, 0x00000000fec0b6f0, 0x00000000fedb0000)
  from space 192K,   0% used [0x00000000fedb0000, 0x00000000fedb0000, 0x00000000fede0000)
  to   space 192K,   0% used [0x00000000fede0000, 0x00000000fede0000, 0x00000000fee10000)
 tenured generation   total 8196K, used 6092K [0x00000000ff2a0000, 0x00000000ffaa1000, 0x0000000100000000)
   the space 8196K,  74% used [0x00000000ff2a0000, 0x00000000ff893390, 0x00000000ff893400, 0x00000000ffaa1000)
 Metaspace       used 3807K, capacity 4540K, committed 4864K, reserved 1056768K
  class space    used 420K, capacity 428K, committed 512K, reserved 1048576K

设置新生代比例参数

-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
-Xmn    新生代大小,一般设为整个堆的1/3到1/4左右

-XX:SurvivorRatio    设置新生代中eden区和from/to空间的比例关系n/1
    public static void main(String[] args) {
        //-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
        //-XX:NewRatio=老年代/新生代
        byte[] b = null;
        for (int i = 0; i < 10; i++) {
            b = new byte[1 * 1024 * 1024];
        }
    }
[GC (Allocation Failure) [DefNew: 507K->255K(768K), 0.0013037 secs] 507K->430K(20224K), 0.0013717 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [DefNew: 767K->109K(768K), 0.0034085 secs] 942K->539K(20224K), 0.0035385 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [DefNew: 621K->155K(768K), 0.0011903 secs] 1051K->586K(20224K), 0.0012244 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 def new generation   total 768K, used 326K [0x00000000fec00000, 0x00000000fed00000, 0x00000000fed00000)
  eden space 512K,  33% used [0x00000000fec00000, 0x00000000fec2aa90, 0x00000000fec80000)
  from space 256K,  60% used [0x00000000fecc0000, 0x00000000fece6f08, 0x00000000fed00000)
  to   space 256K,   0% used [0x00000000fec80000, 0x00000000fec80000, 0x00000000fecc0000)
 tenured generation   total 19456K, used 10670K [0x00000000fed00000, 0x0000000100000000, 0x0000000100000000)
   the space 19456K,  54% used [0x00000000fed00000, 0x00000000ff76ba28, 0x00000000ff76bc00, 0x0000000100000000)
 Metaspace       used 3298K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 359K, capacity 388K, committed 512K, reserved 1048576K

设置新生与老年代参数

基本策略:尽可能将对象预留在新生代,减少老年代的GC次数。

-Xms20m -Xmx20m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC -XX:NewRatio=2
[GC (Allocation Failure) [DefNew: 2718K->1617K(5120K), 0.0031155 secs] 2718K->1617K(18816K), 0.0032612 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [DefNew: 4790K->1044K(5120K), 0.0016988 secs] 4790K->1634K(18816K), 0.0017286 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [DefNew: 4198K->1024K(5120K), 0.0006546 secs] 4788K->1635K(18816K), 0.0006926 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 def new generation   total 5120K, used 4231K [0x00000000fec00000, 0x00000000ff2a0000, 0x00000000ff2a0000)
  eden space 3456K,  92% used [0x00000000fec00000, 0x00000000fef21c88, 0x00000000fef60000)
  from space 1664K,  61% used [0x00000000ff100000, 0x00000000ff2000c8, 0x00000000ff2a0000)
  to   space 1664K,   0% used [0x00000000fef60000, 0x00000000fef60000, 0x00000000ff100000)
 tenured generation   total 13696K, used 610K [0x00000000ff2a0000, 0x0000000100000000, 0x0000000100000000)
   the space 13696K,   4% used [0x00000000ff2a0000, 0x00000000ff338b40, 0x00000000ff338c00, 0x0000000100000000)
 Metaspace       used 3244K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 353K, capacity 388K, committed 512K, reserved 1048576K

内存溢出解决办法

设置堆内存大小

	public static void main(String[] args) throws InterruptedException {
		byte[] bytes1 = new byte[5 * 1024 * 1024];
	}
-Xms5m -Xmx5m -XX:+PrintGCDetails -XX:+UseSerialGC
[GC (Allocation Failure) [DefNew: 1615K->192K(1856K), 0.0015666 secs][Tenured: 401K->592K(4096K), 0.0017534 secs] 1615K->592K(5952K), [Metaspace: 3202K->3202K(1056768K)], 0.0034064 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [Tenured: 592K->574K(4096K), 0.0016865 secs] 592K->574K(5952K), [Metaspace: 3202K->3202K(1056768K)], 0.0017093 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 def new generation   total 1856K, used 73K [0x00000000ffa00000, 0x00000000ffc00000, 0x00000000ffc00000)
  eden space 1664K,   4% used [0x00000000ffa00000, 0x00000000ffa12798, 0x00000000ffba0000)
  from space 192K,   0% used [0x00000000ffbd0000, 0x00000000ffbd0000, 0x00000000ffc00000)
  to   space 192K,   0% used [0x00000000ffba0000, 0x00000000ffba0000, 0x00000000ffbd0000)
 tenured generation   total 4096K, used 574K [0x00000000ffc00000, 0x0000000100000000, 0x0000000100000000)
   the space 4096K,  14% used [0x00000000ffc00000, 0x00000000ffc8f990, 0x00000000ffc8fa00, 0x0000000100000000)
 Metaspace       used 3239K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 356K, capacity 388K, committed 512K, reserved 1048576K
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
-Xms5m -Xmx10m -XX:+PrintGCDetails -XX:+UseSerialGC
[GC (Allocation Failure) [DefNew: 1615K->192K(1856K), 0.0017103 secs][Tenured: 402K->593K(4096K), 0.0017234 secs] 1615K->593K(5952K), [Metaspace: 3204K->3204K(1056768K)], 0.0035308 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 def new generation   total 1920K, used 97K [0x00000000ff600000, 0x00000000ff810000, 0x00000000ff950000)
  eden space 1728K,   5% used [0x00000000ff600000, 0x00000000ff618738, 0x00000000ff7b0000)
  from space 192K,   0% used [0x00000000ff7b0000, 0x00000000ff7b0000, 0x00000000ff7e0000)
  to   space 192K,   0% used [0x00000000ff7e0000, 0x00000000ff7e0000, 0x00000000ff810000)
 tenured generation   total 6848K, used 5713K [0x00000000ff950000, 0x0000000100000000, 0x0000000100000000)
   the space 6848K,  83% used [0x00000000ff950000, 0x00000000ffee4688, 0x00000000ffee4800, 0x0000000100000000)
 Metaspace       used 3285K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 357K, capacity 388K, committed 512K, reserved 1048576K

设置栈内存大小

栈溢出产生于递归调用,循环遍历是不会的,但是循环方法里面产生递归调用, 也会发生栈溢出。

解决办法: -Xss5m 设置最大调用深度

    private static int count;

    public static void main(String[] args) {
        count();
    }
	
    public static void count() {
        try {
            count++;
            count();
        } catch (Throwable e) {
            System.out.println("最大深度:" + count);
            e.printStackTrace();
        }
    }

-Xss1m

最大深度:12234
java.lang.StackOverflowError
	at sun.misc.Unsafe.compareAndSwapLong(Native Method)

-Xss2m

最大深度:68047
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message transform method call failed at JPLISAgent.c line: 844
java.lang.StackOverflowError

Tomcat内存溢出

在catalina.sh 修改JVM堆内存大小

JAVA_OPTS="-server -Xms800m -Xmx800m -XX:PermSize=256m -XX:MaxPermSize=512m -XX:MaxNewSize=512m"

常用参数

堆相关

参数 含义
-XX:InitialHeapSize=100M 设置JVM初始堆内存,简写:-Xms100M
-XX:MaxHeapSize=100M 设置JVM最大堆内存,简写:-Xms100M
-XX:NewSize=20M 设置年轻代的大小
-XX:MaxNewSize=50M 年轻代最大大小
-XX:OldSize=50M 设置老年代大小
-XX:MetaspaceSize=50M 设置方法区大小
-XX:MaxMetaspaceSize=50M 方法区最大大小
-XX:+HeapDumpOnOutOfMemoryError 启动堆内存溢出打印,当JVM堆内存发生溢出时,也就是OOM,自动生成dump文件
-XX:HeapDumpPath=heap.hprof 指定堆内存溢出打印目录,表示在当前目录生成一个heap.hprof文件
-XX:ThreadStackSize=128 设置每个线程的堆栈大小,简写:-Xss100 ,3000-5000最佳

GC相关

参数 含义 说明
-XX:+UseParallelGC 使用UseParallelGC 新生代,吞吐量优先
-XX:+UseParallelOldGC 使用UseParallelOldGC 老年代,吞吐量优先
-XX:+UseConcMarkSweepGC 使用CMS 老年代,停顿时间优先
-XX:+UseG1GC 使用G1GC 新生代,老年代,停顿时间优先
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:g1-gc.log 打印出GC日志 可以使用不同的垃圾收集器,对比查看GC情况
-XX:G1HeapWastePercent 允许的浪费堆空间的占比 默认是10%,如果并发标记可回收的空间小于10%,则不会触发MixedGC
-XX:MaxGCPauseMillis=200ms G1最大停顿时间 暂停时间不能太小,太小的话就会导致出现G1跟不上垃圾产生的速度。最终退化成FullGC。所以对这个参数的调优是一个持续的过程,逐步调整到最佳状态
-XX:ConcGCThreads=n 并发垃圾收集器使用的线程数量 默认值随JVM运行的平台不同而不同
-XX:G1MixedGCLiveThresholdPercent=65 混合垃圾回收周期中要包括的旧区域设置占用率阈值 默认占用率为 65%
-XX:G1MixedGCCountTarget=8 设置标记周期完成后,对存活数据上限为G1MixedGCLIveThresholdPercent的旧区域执行混合垃圾回收的目标次数 默认8次混合垃圾回收,混合回收的目标是要控制在此目标次数以内
-XX:G1OldCSetRegionThresholdPercent=1 描述Mixed GC时,Old Region被加入到CSet中 默认情况下,G1只把10%的Old Region加入到CSet中
-XX:InitiatingHeapOccupancyPercent 启动并发GC周期时堆内存使用占比 G1之类的垃圾收集器用它来触发并发GC周期,基于整个堆的使用率,而不只是某一代内存的使用比. 值为 0 则表示”一直执行GC循环”. 默认值为 45

其他

参数 含义 说明
-XX:CICompilerCount=3 最大并行编译数 如果设置大于1,虽然编译速度会提高,但是同样影响系统稳定性,会增加JVM崩溃的可能
-XX:NewRatio 新老生代的比值 如-XX:Ratio=4,则表示新生代:老年代=1:4,也就是新生代占整个堆内存的1/5
-XX:SurvivorRatio 两个S区和Eden区的比值 如-XX:SurvivorRatio=8,也就是(S0+S1):Eden=2:8,也就是一个S占整个新生代的1/10
-XX:MaxTenuringThreshold=6 提升年老代的最大临界值 默认值为 15

JVM参数配置总结

默认情况不做任何JVM参数设置JVM会工作的很好。但是,在JVM启动参数中,可以设置跟内存、垃圾回收相关参数,针对不同应用,不断仔细调优后能获得最佳性能。

调优核心:

GC的时间足够的小

GC的次数足够的少

发生Full GC的周期足够的长

1.GC时间与GC次数是相悖的,要想GC时间小必须要一个更小的堆,要保证GC次数足够少,必须保证一个更大的堆,只能取其平衡。

2.针对JVM堆的设置,一般可以通过-Xms -Xmx限定其最小、最大值,防止垃圾收集器在最小、最大之间收缩堆而产生额外的时间,通常把最大、最小设置为相同的值

3.年轻代和年老代根据默认比例(1:2)分配堆内存,可以通过调整二者之间的比率NewRadio来调整二者间的大小,也可以针对回收代,如年轻代,通过-XX:newSize -XX:MaxNewSize设置其绝对大小。同样,防止年轻代的堆收缩,通常会把-XX:newSize -XX:MaxNewSize设置为同样大小

4.年轻代和年老代设置的设置比例是需要根据实际场景调优设置的。

更大的年轻代必然导致更小的年老代,大的年轻代会延长普通GC的周期,但会增加每次GC的时间,小的年老代会导致更频繁的Full GC

更小的年轻代必然导致更大年老代,小的年轻代会导致普通GC很频繁,但每次的GC时间会更短,大的年老代会减少Full GC的频率

根据对象生命周期的分布情况判断:

如果应用存在大量的临时对象,应该选择更大的年轻代

如果存在相对较多的持久对象,年老代应该适当增大。

在多数应用中没有明显特性,可根据以下两点考虑:

本着Full GC尽量少的原则,让年老代尽量缓存常用对象,JVM的默认比例1:2也是这个道理 

在不影响Full GC的前提下,根据实际情况加大年轻代,如把比例控制在1:1。但应该给年老代至少预留1/3的增长空间

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/136871.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!