格式一般都是由-X构成
-Xms:如果在运行的时候给定这个参数,表示初始化堆大小,这个堆是包含了Eden,包含了old,整个堆的初始化大
小,比如你给他800M,那它就会根据800M去分配年轻代和老年代,及持久代
-Xmx: 最大堆大小,初始是多大,如果不够最多能够申请到多大,允许申请的最大大小
-XX:NewSize=n 这个是设置年轻代的大小,上面两个颗粒度更粗一些,这里的颗粒度很细一些,这里是年轻代的
大小
-XX:NewRatio=n 这里也是设置年轻代的大小,不同的是NewSize给的是具体的单位,比如800M,500M,ratio是
比率,按照多大的比率去设置各代的大小
-XX:SurvivorRatio=n Survivor比例是设置Suvivor区的比例,是s0和s1相对于Eden区域的大小,
年轻代默认的比例是8:1:1,8是Eden,1和1是s0和s1,那么我们可能会根据需要去调整,缩小Eden区的大小,
扩大Survivor区的大小,s0或者s1的大小,那么我们就可以用这个命令了,不让他8:1:1走
-XX:MaxPermSize=n Permanent单词,持久的单词
以上这部分是设置内存空间的大小
往下是设置收集器的
-XX:+UseSerialGC 设置串行收集器来手机年轻代
-XX:+UseParallelGC 如果我想用Parallel并行收集器
-XX:+UseParallelOldGC 如果我们想要老年代的并行收集器就用它
-XX:+UseConcMarkSweepGC 注意CMS不叫ConcurrentMarkSweep,它简写了,这后面不需要跟任何的参数,这个
是收集器的指定
以上这块是对收集器的指定
在JAVA的lang包下,其实也提供了通过代码能够获取JVM信息的类的实现,
我现在缩写的这一块代码就是能够获取当前JVM当中的虚拟机的信息,除了能够通过命令来获取以外,我们还可以
通过代码来实现
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.util.List;
public class Test{
public static void main(String[] args) throws InterruptedException {
List<GarbageCollectorMXBean> list = ManagementFactory.getGarbageCollectorMXBeans();
for (GarbageCollectorMXBean gc : list) {
System.out.println(gc.getName());
}
}
}
PS Scavenge
PS MarkSweep
通过ManagementFactory的工具类去获取当前虚拟机的回收器的信息,但是虚拟机有几个回收器,有几个收集器,
新生代有一个,老年代也得有,它返回的能是一个吗?能只返回一个GC吗,答案是不能,所以它返回的是一堆,其实
就是两个,所以返回一个list, GargabageCollectorMXBean封装虚拟机当前的信息,通过每个对象的getName就
可以获取到他虚拟机现在正在用的回收器的名称,现在我用的JDK是1.7的
第一个输出的是年轻代的Scavenge, 第二个是老年代的MarkSweep,说明年轻代用的是Parallel Scanvenge,
年轻代在1.7.2这个版本JDK里,年轻代的收集器是Parallel Scavenge,然后永久代用的CMS,CMS能不能和他配合
着工作
我现在还可以去改它的收集器,你想去用什么你就去改什么,比如我们相拥 Serial GC,就使用命令
-XX:+UseSerialGC,然后怎么去给你的虚拟机去设置这些命令呢,我们要想一点,肯定是虚拟机启动时指定的,
3而不是在虚拟机运行时给定的,以往我们是点右键 Run,现在我们是Run Configuration
找到你要执行文件的arguments参数选项
然后在这里把你的参数加进去
以上的参数都可以加进去,并且他们之间不需要通过逗号分隔,直接用空格分隔就可以了,我现在改收集器了,
改了一个新生代的收集器,Serial GC就是新生代的收集器,一运行就打印出
新生代输出的名字并不叫Serial,而是Copy
然后我们再换一个收集器
G1是一个收集器可以跨区回收,年轻代可以,老年代也可以.
所以我们在这个位置可以给定参数
包括可以在里面打印GC的信息
这个很简单,直接复制就可以用的
堆大小设置
JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32bit 还是 64bit操作系统),它的限制方式是不一样
的,系统可以用虚拟内存限制,可以用物理内存限制,32位系统下,一般限制在1.5G~2G,堆的大小在32位系统下最大
不能超过2个G或者1.5个G,64位系统则对内存无限制,但是即使是这样它还是有一个下限的,你总不能超过总内存的
大小吧,总存储空间的大小吧.
典型的设置
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
看到这个想到什么了,它是通过黑窗口来做的,-Xmx是堆最大可用内存,-Xms是初始堆大小,-Xmn2g设置年轻代大小
整个堆大小=年轻代大小+老年代大小+持久代大小,最后合并成就是我们整个堆的大小,持久代一般不用分很大,
持久代64M就足够了,不要想着有很多东西存在持久带里,-Xss128k是设置每个线程的堆栈大小,线程堆的大小,
JDK1.5以后每个线程堆栈大小为1M,以前的每个版本为256K,比如说我们经常会遇到栈溢出,就和设置这个大小有关
你设置越大,栈溢出的几率就越小,但是有可能会有浪费,如果设置过小,栈溢出的风险就更大,所以这一块我们建议
能不动就不动,因为虚拟机默认给你的大小已经完全够用了,除非你要做一些科学计算,我天天玩递归,玩数学运算,
递归老长了,递归的次数老频繁了,这个时候就应该加一个这种大小,这种方式是详细指定
java -Xmx3550m -Xms3550m -Xss 128k -XX:NewRatio=4
NewRatio是按照比例去设置,设置为4表示年轻代与老年代所占比值为1:4,年轻代占5分之一
还有Survivor Ratio设置s0和s1的比例
-XX:MaxPermSize 设置持久代的大小
-XX:MaxTenuringThreshold=0 设置垃圾最大年龄,垃圾回收的一个阀值,如果这个对象的年龄到15次还活着,
那说明没问题了,直接进入老年代里面,如果15次就回收了,就回收了
有两种方式给定参数,一个是命令窗口的方式,一种是Eclipse->Run->Configuration->Arugument
吞吐量优先的并行收集器
并行收集器主要以达到一定的吞吐量为目标,适用于科学计算和后台处理等.
以上的配置我们主要是考虑性能,接下来我们是考虑吞吐量的,其实我个人觉得考虑吞吐量不太实用我们B/S编程
ParallelGC本来就是考虑吞吐量的,所以要首选这个GC,
-XX:ParallelGCThreads=20 Parallel GC就是并行的,这里就是设置垃圾回收线程数的,所以现在给了20个并行
线程做垃圾回收,这块不是给越大越好,它最大不能超过这台服务器的逻辑内核数,设置完也没用,比如我现在这个
机器给他设置20,一点用都没有,它最多能用上4个,因为我这个CPU是逻辑4核的,单CPU超线程的,i5,4核的,
调优总结
年轻代大小选择
JVM调优策略是什么,可以把它换成Server端的,一次分配堆大小,GC,但这些也不是全部的调优,这个颗粒度比较粗
了,如果你想做更细粒度的调优,这块只能给你理论上宏观上的
1. 响应时间的应用,尽可能的设置大,年轻代尽可能设大,直接接近系统的最低响应时间的限制,根据实际情况
选择,在此种情况下,年轻代收集发生的频率也是最小的,减少达到年老代的现象.
2. 吞吐量优先的应用: 尽可能的设置大,可能达到Gbit的程度,因为对响应时间没有要求,垃圾收集可以并行进行,
一般适合8CPU以上的应用.
3. 响应时间优先的应用: 年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续
时间等一些参数,如果堆设置太小,可能会造成内存碎片,高回收频率以及应用暂停而使用传统的标记清除方式,
如果堆大了,则需要较长的时间收集
最优化的方案,一般需要参考以下数据获得:
1. 并发垃圾收集信息
2. 持久代并发收集次数
3. 传统 GC 信息
4. 花在年轻代和老年代回收上的时间比例