有关内存的常用配置参数

几个非常常用的内存配置参数:
  -Xms
  JVM启动时申请的初始Heap值(堆),默认为操作系统物理内存的1/64但小于1G。默认当空余堆内存大于70%时,JVM会减小heap的大小到-Xms指定的大小,可通过-XX:MaxHeapFreeRation=来指定这个比列。Server端JVM最好将-Xms和-Xmx设为相同值,避免每次垃圾回收完成后JVM重新分配内存,也可以减少垃圾回收次数开发测试机JVM可以保留默认值。(例如:-Xms4g)。
  -Xmx
  JVM可申请的最大Heap值(堆),默认值为物理内存的1/4但小于1G,默认当空余堆内存小于40%时,JVM会增大Heap到-Xmx指定的大小,可通过-XX:MinHeapFreeRation=来指定这个比列。最佳设值应该视物理内存大小及计算机内其他内存开销而定。(例如:-Xmx4g)
看个例子,做个对比试验,-Xms和-Xmx设为不同和相同值,用代码对比一下,看看回收次数的变化:
先给jvm这么一个配置:-Xms5M -Xmx20M -XX:+PrintGCDetails -XX:+UseSerialGC
  解释:1.-XX:+PrintGCDetails:配置垃圾回收日志,让其在控制台中显示出来,2.-XX:+UseSerialGC(串行垃圾回收器,默认,可以不配置)
  总结:减少垃圾回收次数的两个方案:1.尽可能的让堆内存区域大,2.让-Xms(堆内存初始值)和-Xmx(堆内存最大值)相等,限制堆内存的这种伸缩变化能力。(伸缩变化能力:比如说如果初始值比较小的话,在new一个对象时,新生代Eden(伊甸园)就容易被填满,一旦被填满就会触发minor gc(垃圾回收)minor gc(垃圾回收)会消耗资源,系统就会变得卡顿
public class JvmTest {
    public static void main(String[] args) {
        byte[] bs = new byte[1*1024*1024];
        System.out.println("分配了1M的内存空间");
        jvmInfo();
        byte[] bs1 = new byte[4*1024*1024];
        System.out.println("分配了4M的内存空间");
        jvmInfo();
    }
    public static String toM(long byteNum) {
        float num = byteNum/(1024*1024);
        DecimalFormat df = new DecimalFormat("0.00");
        String str = df.format(num);
        return str;
    }
    public static void jvmInfo() {
        //获取配置的最大内存
        long maxMemory = Runtime.getRuntime().maxMemory();
        System.out.println("maxMemory:" + maxMemory + "字节," + toM(maxMemory) + "M");

        //获取堆空闲的内存大小
        long freeMemory = Runtime.getRuntime().freeMemory();
        System.out.println("freeMemory:" + maxMemory + "字节," + toM(freeMemory) + "M");

        //获取堆当前使用掉的内存大小
        long totalMemory = Runtime.getRuntime().totalMemory();
        System.out.println("totalMemory:" + maxMemory + "字节," + toM(totalMemory) + "M");
    }
}

解释:[GC [DefNew: 273088K(新生代垃圾回收之前的值) -> 5561K(新生代垃圾回收之后的值)(307200K), 0.0186715 secs] 278084K(堆内存垃圾回收之前的值) -> 10558K(堆内存垃圾回收之后的值)(989888K), 0.0187027 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]

  -Xmn (jdk1.4以后将-XX:NewSize和-XX:MaxNewSize合一,因为我们设置他们的时候也建议设置一样大)
  Java Heap Young区大小(新生代)。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小(相对于HotSpot 类型的虚拟机来说)。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。(例如:-Xmn2g)
老年代用于存放经过多次新生代GC仍然存活的对象,例如缓存对象,新建的对象也有可能直接进入老年代(不是说所有进入老年代的对象都是长寿对象),主要有两种情况:
1、大对象,可通过启动参数设置-XX:PretenureSizeThreshold=1024(单位为字节,默认为0)来代表超过多大时就不在新生代分配,而是直接在老年代分配。
2、大的数组对象,且数组中无引用外部对象。老年代所占的内存大小为-Xmx对应的值减去-Xmn对应的值。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。(这个异常主要看两点:1.堆内存区域是不是太小了,2.程序里是不是有内存泄露)
  -Xss(本地方法栈)
  Java每个线程的Stack大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。(推荐:小系统:-Xss128K,大系统:-Xss256K)
  总结:1.每个服务器的物理内存是有上线的,一个栈对应一个线程,如果线程栈大小设置大了的话,就意味着操作系统创建线程数就不多,线程数不多服务器并发处理就弱,如果大访问量进来,线程数不够,就会造成线程数以外的用户进行排队等待,出现打开网页n久都打不开。2.如果线程栈大小设置小了的话,可以创建会多很多个线程,但是操作系统对一个进程内的线程数还是有限制的,不能无线生成,所以线程栈设置太小也达不到最优。
 -XX:PermSize(方法区)
  持久代(方法区)的初始内存大小。(例如:-XX:PermSize=64m)
 -XX:MaxPermSize(方法区)
  持久代(方法区)的最大内存大小。(例如:-XX:MaxPermSize=512m)
 -XX:+MaxTenuringThreshold=10(方法区)
  垃圾的最大年龄,代表对象在Survivor区经过10次复制以后才进入老年代。如果设置为0,则年轻代对象不经过Survivor区,直接进入老年代。
注意:tomcat中的配置内存参数可以放在 catalina.sh(Linux)或者catalina.bat(Windows)的第二行:
set JAVA_OPTS=%JAVA_OPTS% -server -Xms1800m -Xmx1800m -Xmn600m -XX:PermSize=512M -XX:MaxPermSize=512m -Xss128K -XX:+PrintGCDetails
补充:catalina.sh(Linux)或者catalina.bat(Windows)配置文件中的rem是注释的意思
总结:JVM参数配置优化上面,没有一个固定的值,一般都是通过具体的情况去做具体的分析。可以通过压力测试软件,通过压力测试的参数和报出的异常信息来去修改JVM参数配置,不同的程序,不同的访问量配置的都不同。
posted @ 2019-10-10 11:26  Java-Legend  阅读(875)  评论(0编辑  收藏  举报