JVM内存参数详解以及配置调优

  • 格式:docx
  • 大小:32.19 KB
  • 文档页数:13

JVM的结构 从功能上分,Java虚拟机主要由六个部分组成,可以分成三类: 第一类:JVM API:就是我们最常用的Java API,它是开发人员和Java交互的入口,它主要是JAVA_HOME/jre/lib下的运行时类库rt.jar和编译相关的tools.jar

第二类:JVM内部组件 类装载器(ClassLoader):将Byte Array的 .class文件装载、链接和初始化。 内存管理(Memory Managent):为对象分配内存,以及释放内存。后者就是垃圾回收Garbage Collector(GC)。由于JVM最复杂的、最影响性能的就是GC,所以内存管理一般就指垃圾回收。 诊断接口(Diagostics Interface):这主要体现在JVMTI(jdk1.4下的JVMPI和JVMDI),它主要用来诊断程序的问题和性能,一般提供给工具厂商实现。如eclispe IDE下的debug功能,Jprofiler性能调优工具。 类解释器(Interpreter):解释装载进虚拟机的class对象,包括JIT等特性相关。

第三类:平台相关接口(Platform Interface):主要为了跨操作系统平台重用JVM代码,不过,它和我们开发人员关系不大。 在以上六个组件中,我们开发人员最关心的是ClassLoader和GC,用Java做系统框架、容器和它们密切相关。做业务系统时一些基础代码 也和它们打交道,譬如最常用的 Class.forName(),Thread.currentThread.getContextClassLoader()。我们仔细想想,为什么是 上面两个问题?因为,它和我们class的整个生命周期最为相关:怎么将一个class和相关class加载进来,class实例什么时候创建,什么时候 被销毁? 所以,下面的部分我们要专门讨论这些问题。

在JVM中有两种垃圾方式,一种叫做Minor(次收集),另一种叫做Major(主收集)。其中Minor在Young Generation的空间被 对象全部占用后执行,主要是对Young Generation中的对象进行垃圾收集。而Major是针对于整个Heap size的垃圾收集。其中 Minor方式的收集经常发生,并且Minor收集所占用的系统时间小。Major方式的垃圾收集则是一种“昂贵”的垃圾收集方式,因为在Major要对 整个Heap size进行垃圾收集,这会使得应用停顿的时间变得较长。

java -jar -server -verbose:gc -XX:+UseParNewGC -Xmn8m -Xms32m -Xmx32m SwingSet2.jar 使用了-XX:+UseParNewGC选项的minor收集的时间要比不使用的时候优。 java -jar -verbose:gc -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -Xmn64m -Xms256m -Xmx256m SwingSet2.jar 采用-XX:+UseConcMarkSweepGC选项在Heap Size 比较大而且Major收集时间较长的情况下使用更合适  堆(Heap)和非堆(Non-heap)内存 按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给 自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法 的代码都在非堆内存中。  堆内存分配 JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最 大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70% 时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。  非堆内存分配 JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。  JVM内存限制(最大值) 首先JVM内存限制于实际的最大物理内存(废话!呵呵),假设物 理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个 限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了。

jvm的调整没什么技巧,只有一些原则,要根据自己应用的特点来设定调优的目标,这里收集了一些内容,权当记录

Java heap (Xmx, Xms) 和java进程的heap是两回事情 java进程的heap包含: Java Heap Permanent Generation Thread stacks Native code Directly allocated memory Code generation Garbage collection TCP buffers

因此我们在设置,jvm参数的时候得小心一点,一般我们会设置java heap 和 perm gen,结合操作系统内存的大小和应用特点,选取一个合理的值。

-Xms/-Xmx java heap并不是越大越好,对他的一般优化原则是够用的情况下,尽可能的小,因为太大的话会浪费内存,同时影响GC的效率

-XX:NewSize/-XX:NewRatio 一般设置为java heap的25%-33%,太大或者太小都会影响GC,要根据应用的特点,对象生命长短周期的比例来调整

GC相关调整的目标: * 短生命周期的对象不要进入Old区 * 短生命周期的对象在minor GC的时候干掉 * 长生命周期的对象要放到Old区 * 长生命周期的对象可以被Full GC清理掉,但是Full GC要调整到尽量少发生

不管采用什么算法,GC总是会导致应用暂停的,这个时间长短从毫秒到秒之间不等,因此会影响应用的相应时间,多长的停顿在接受范围内取决于应用的特征,可以通过设置GC停顿的时间来调整(注意只是期望的时间,而不是绝对) -XX:MaxGCPauseMillis -XX:MaxGCMinorPauseMillis ,一般设置比较短的停顿时间会导致相对较频繁的GC,根据应用的情况来调整

Xms: java heap初始化时的大小。默认情况是机器物理内存的1/64。这个主要是根据应用启动时消耗的资源决定,分配少了申请起来会降低启动速度,分配多了也浪费。 Xmx:java heap的 最大值,默认是机器物理内存的1/4,最大也就到1G。这个值决定了最多可用的Java Heap Memory,分配过少就会在应用需要大量内存作缓存或者零时对象时出现OOM的问题,如果分配过大,那么就会产生上文提到的第二类OOM。所以如何配置 还是根据运行过程中的分析和计算来确定,如果不能确定还是采用默认的配置。 Xmn:java heap新 生代的空间大小。在GC模型中,根据对象的生命周期的长短,产生了内存分代的设计:青年代(内部也分成三部分,类似于整体划分的作用,可以通过配置来设置 比例),老年代,持久代。每一代的管理和回收策略都不相同,最为活跃的就是青年代,同时这部分的内存分配和管理效率也是最高。通常情况下,对于内存的申请 优先在新生代中申请,当内存不够时会整理新生代,当整理以后还是不能满足申请的内存,就会向老年代移动一些生命周期较长的对象。这种整理和移动会消耗资 源,同时降低系统运行响应能力,因此如果青年代设置的过小,就会频繁的整理和移动,对性能造成影响。那是否把年青代设置的越大越好,其实不然,年青代采用 的是复制搜集算法,这种算法必须停止所有应用程序线程,服务器线程切换时间就会成为应用响应的瓶颈(当然永远不用收集那么就不存在这个问题)。老年代采用 的是串行标记收集的方式,并发收集可以减少对于应用的影响。 Xss:线程堆栈最大值。允许更多的虚拟内存空间地址被Java Heap使用。 以下是sun公司的性能优化白皮书中提到的几个例子: 1.对于吞吐量的调优。机器配置:4G的内存,32个线程并发能力。 java -Xmx3800m -Xms3800m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -Xmx3800m -Xms3800m 配置了最大Java Heap来充分利用系统内存。

-Xmn2g 创建足够大的青年代(可以并行被回收)充分利用系统内存,防止将短期对象复制到老年代。 -Xss128 减少默认最大的线程栈大小,提供更多的处理虚拟内存地址空间被进程使用。 -XX:+UseParallelGC 采用并行垃圾收集器对年青代的内存进行收集,提高效率。 -XX:ParallelGCThreads=20 减少垃圾收集线程,默认是和服务器可支持的线程最大并发数相同,往往不需要配置到最大值。 2.尝试采用对老年代并行收集 java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC -Xmx3550m -Xms3550m 内存分配被减小,因为ParallelOldGC会增加对于Native Heap的需求,因此需要减小Java Heap来满足需求。 -XX:+UseParallelOldGC 采用对于老年代并发收集的策略,可以提高收集效率。 3.提高吞吐量,减少应用停顿时间 java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:ParallelGCThreads=20 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:SurvivorRatio=8 -XX:TargetSurvivorRatio=90 -XX:MaxTenuringThreshold=31 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC 选择了并发标记交换收集器,它可以并发执行收集操作,降低应用停止时间,同时它也是并行处理模式,可以有效地利用多处理器的系统的多进程处理。 -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=31 表示在青年代中Eden和Survivor比例,设置增加了Survivor的大小,越大的survivor空间可以允许短期对象尽量在年青代消亡。 -XX:TargetSurvivorRatio=90 允许90%的空间被占用,超过默认的50%,提高对于survivor的使用率。