以前总听说jvm调优 觉得特别神秘 相信很多人也跟我有同样的想法吧觉得这应该是架构师级别才能玩的东西
我们虽然没有办法去碰java里面的东西但是对于一般的调优还是可以做到的,这也是每个java程序员必须要走的路
首先来看 -Xms 与-Xmx这两个参数 指定的是java的堆内存的大小 当空余堆内存小于 40% 时,JVM 就会增大堆直到 -Xmx 的最大限制 当超过这个的时候就会报内存溢出 当空余堆内存大于 70% 时,JVM 会减少堆直到-Xms 的最小限制 这样就会重复的申请内存 从而导致性能大起大落,给出的建议就是调成一样,防止重复申请内存
public class Main {
public byte [] res=new byte[10000000];
private static long s=0;
public static void main(String[] args) {
// write your code here
System.out.println("args = " + args);
List<Object> objects=new ArrayList<>();
while (true){
Main main = new Main();
objects.add(main);
System.out.println("objects.size() = " + objects.size());
;
}
}
}
objects.size() = 176
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.company.Main.<init>(Main.java:8)
可以看到当存到176的时候内存溢出了 当把运行参数设置为
-Xms600M -Xmx600M
控制台打印与
objects.size() = 56
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
发现只存了 56个就报栈溢出异常了
改成
**-Xms1000M -Xmx1000M **
的时候发现当控制台打印到95的时候报溢出错误了
所以在可使用的内存中当这两个值越大,你程序的堆内存越大
但是 这个值越大就越好吗?????
其实并不是这样的 首先在一台电脑里面一个进程他的能得到的最大内存是有限制的 你用-xmx 和-xms 这两个来加大堆的空间 带来的问题就是 这个栈内存减小程序并发性降低
对于高并发,创建对象不多的项目,可以降低Xmx的配置
对于低并发,创建对象多的项目, 可以适当提高,Xmx的配置
关于栈的调优 配置这里涉及到的有这个参数-Xss:栈空间的大小一般来栈空间越大可以递归的次数越多
public class Main {
private static long s=0;
public static void main(String[] args) {
digui(0);
}
public static void digui(int r){
System.out.println("++r = " + ++r);
digui(r);
}
}
//++r = 9357
Exception in thread "main" java.lang.StackOverflowError
在什么都不配置的情况下 递归深度为9357
接下来配置
-Xss100k
++r = 976
Exception in thread "main" java.lang.StackOverflowError
-Xss512k
++r = 5204
Exception in thread "main" java.lang.StackOverflowError
可以看到当这个值越大那栈内存就越大可以调用的次数越多
简而言之:
-Xss 这个值越大一个栈的栈内存就越大 但是 在同样大小的内存里面 单个栈越大那你能支撑的多线程就越少 如果向那种爬虫项目 本来也不需要执行多少代码 就是要大并发量那这个值就可以调小 但是像一些需要很大的递归需要的可以适当的把这个值调大一点
-XX:+DisableExplicitGC
在 程序代码中不允许有显示的调用“System.gc()”
public class Main {
public static void data(){
byte[] w=new byte[1024*1024];
}
public static void main(String[] args) {
long l = System.currentTimeMillis();
ArrayList<Main> mains = new ArrayList<>();
for (int i = 0; i <1000 ; i++) {
mains.add(new Main());
System.gc();
}
long millis = System.currentTimeMillis();
System.out.println(millis-l);
}
}
//3852
该代码里面我们每次放入都调用一次gc(); 最后打印为3852
现在我配置该参数
-XX:+DisableExplicitGC
时间为1
那是不是就说明应该在调优的过程中应该配置呢?
其实不是 如果说你知道在处理完你的逻辑之后会产生一大堆无用的对象 那你调用并且这段时间访问人数很少那你调用一下gc清理垃圾无可厚非 但是如果你配置了这个不响应 那你就只有等着jvm自动回收
以上对jvm 的配置比较粗犷 下面介绍对jvm进行更加详细的配置
-XX:MaxTenuringThreshold:设置垃圾最大年龄 值越大对象在新生代的
**-XX:NewSize:设置新生代内存大小。
-XX:MaxNewSize:设置最大新生代新生代内存大小
-XX:PermSize:设置持久代内存大小
-XX:MaxPermSize:设置最大值持久代内存大小,永久代不属于堆内存,堆内存只包含新生代和老年代。
-XX:MaxGCPauseMills
最大停顿时间,单位毫秒
GC尽力保证回收时间不超过设定值
-XX:GCTimeRatio
0-100的取值范围
垃圾收集时间占总时间的比
默认99,即最大允许1%时间做GC
**
除了上面的几个 还有一些不是特别重要的重要参数, 但是设置对了确实有奇效
-XX:+CMSParallelRemarkEnabled:在使用 UseParNewGC 的情况下,尽量减少 mark 的时间。
-XX:+UseCMSCompactAtFullCollection:在使用 concurrent gc 的情况下,防止 memoryfragmention,对 live object 进行整理,使 memory 碎片减少。
-XX:+UseFastAccessorMethods:使用 get,set 方法转成本地代码,原始类型的快速优化。
-XX:+UseCMSInitiatingOccupancyOnly:只有在 oldgeneration 在使用了初始化的比例后 concurrent collector 启动收集。
-Duser.timezone=Asia/Shanghai:设置用户所在时区。
-XX:+AggressiveOpts:启用这个参数,则每当 JDK 版本升级时,你的 JVM 都会使用最新加入的优化技术。
网友评论