• 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: 设置元空间的最大值, 默认是-1, 即不限制, 或者说只受限于本地内存的大小

    由于调整元空间的大小需要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;
        public static void redo(){
            count ++;
            redo();
        }
    
        public static void 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

  • 相关阅读:
    java线程——三种创建线程的方式
    java线程——详解Callable、Future和FutureTask
    商品详情页系统的Servlet3异步化实践
    关于servlet3.0中的异步servlet
    Spring中线程池的应用
    Spring中@Async注解实现“方法”的异步调用
    高性能的关键:Spring MVC的异步模式
    SpringBoot+springmvc异步处理请求
    指定Qt程序运行的style,比如fusion(以前没见过QStyleFactory)
    Linux下获取arm的交叉编译工具链
  • 原文地址:https://www.cnblogs.com/ITPower/p/13237572.html
Copyright © 2020-2023  润新知