2.3 JVM内存参数设置

我们可以对运行时数据区的内存进行参数设置. 这是jvm调优的重点. 参数的变化将影响到整体效率

核心参数设置如下:

java -Xms2048M -Xmx1024M -Xss512k -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -jar microservice-eureka-server.jar

这里单独说一下spring boot项目启动的时候如何设置jvm参数? 

tomcat启动直接加载bin目录下catalina.sh文件里面

 

一. 方法区(元空间)参数设置

 

 

在jdk8之前有各区域叫做永久代,在jdk8及以后改名字了,叫做元空间. 这块内存空间占用的是直接的物理内存. 

元空间有一个特点: 可以动态扩容,如果,我们没有设置元空间的上限,那么他可以扩大到整个内存. 比如内存条是8G的,堆和栈分配了4G的空间,那么元空间最多可以使用4G

我们可以通过参数来设置使用的最大内存

-XX:MetaspaceSize=256M     元空间的初始空间大小,以字节位单位,默认是21M,达到该值就会触发full GC,同时收集器会对该值进行调整,如果释放了大量的空间,
                  就适当降低该值,如果释放了很少的空间,提升该值,但最到不超过
-XX:MaxMetaspaceSize设置的值
-XX:MaxMetaspaceSize=256M   设置元空间的最大值,默认是-1,即不限制,或者说只受限于本地内存的大小

对于64位的JVM来说,元空间默认大小是21M,元空间的默认最大值是无上限的,他的上限就是内存空间

  • -XX:MetaspaceSize: 元空间的初始空间大小,默认是21M,达到该值就会触发full GC, 就适当降低该值,但最到不超过-XX:MaxMetaspaceSize设置的值
比如: 
初始值是21M,第一次回收了20M,那么只有1M没有被回收,下一次,元空间会自动调整大小,可能会调整到15M 初始大小依然是21M,第二次回收发现回收了1M,有20M没有被回收,他就会自动扩大空间,可能扩大到30M,也可能是40M
  • -XX:MaxMetaspaceSize: 设置元空间的最大值,或者说只受限于本地内存的大小

由于调整元空间的大小需要full GC,这是非常昂贵的操作,如果应用在启动的时候发生大量的full GC,通常都是由于永久代或元空间发生了大小的调整,基于这种情况,一般建议在JVM参数中将-XX:MetaspaceSize和-XX:MaxMetaspaceSize设置成一样的值,并设置的比初始值还要大,对于8G物理内存的机器来说,一般会将这两个值设置为256M或者512M都可以

建议: 设置元空间值,不设置会怎么样?

不设置默认就是21M,很容易就会放满,通常我们的war可能都是几十M,甚至几个G. 如果我们在启动程序的时候,会启动几分钟. 这很有可能是没有设置元空间的大小.

放满后会发生full GC,然后在扩大一点元空间,扩大到25M,重新开始,过了一会又放满了,再次full GC,在扩大一点,元空间扩大到30M,就这样一直发生full GC,然后一直扩大元空间,直到扩大的元空间大小合适,不再发生full gc,程序才会正常启动运行. 这是个很耗时耗性能的操作,这样的full GC也是没有必要的.

 

二. 栈参数设置

-Xss512k

这个参数就是用来设置栈空间的. 他是设置的一个线程栈占用的空间,一个程序启动后可能有多个线程栈,那么他们占用的空间都是512k

 下面来看一个例子

package com.lxl.jvm;

public class StackOverflowTest {
    /**
     * jvm 设置-Xss128M,(默认是1M)
     */
    static int count = 0;
    void redo(){
        count ++;
        redo();
    }

     main(String[] args) {
        try {
            redo();
        }catch (Throwable e) {
            e.printStackTrace();
            System.out.println(count);
        }
    }

}

这里定义了一个变量count,main方法里调用了redo()方法. 当我们执行main方法的时候,线程栈模型是什么样的呢?

 

 当程序执行到main方法的时候,会在线程栈中开辟一个main方法的栈帧

继续执行,执行到redo()的时候,会在线程栈在开辟一块redo方法栈帧

redo方法里又调用了redo方法. 继续开辟一块redo方法栈帧, 

.......

栈帧是占用内存空间的. 总有一个时刻会把栈内存消耗完. 就会报栈内存溢出了

 

 我们看到程序一共运行了16979次发生了栈溢出.

当栈空间设置的小一些呢?比如256k

 

我们运行看效果

 

 当运行到2079次的时候,发生了栈溢出

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 as

相关文章

jinfo 命令可以用来查看 Java 进程运行的 JVM 参数,命令如下...
原文链接:https://www.cnblogs.com/niejunlei/p/5987611.ht...
java 语言, 开发者不能直接控制程序运行内存, 对象的创建都是...
jvm
1.jvm的简单抽象模型:  2.类加载机制     双亲委派模...
堆外内存JVM启动时分配的内存,称为堆内存,与之相对的,在代...
1.springboot和tomcat2.springcloud的请求如何通过网关鉴权?...