Java内存基本的调优的调优策略
我们知道GC发生的越频繁,就会对整个系统的性能影响越多。那么如何不频繁的发生GC呢?
存活区空间足够大,老年代空间足够大。就是说内存越大GC发生的频率越低,系统性能就越高。
范例:首先取的可用的内存空间量
public static void main(String[] args) {
int rat=1024*1024;
Runtime run=Runtime.getRuntime();
System.out.println("MAX_MEMORY = "+((double)run.maxMemory()/rat)+"M");
System.out.println("TOTAL_MEMORY = "+((double)run.totalMemory()/rat)+"M");
System.out.println("FREE_MEMORY = "+((double)run.freeMemory()/rat)+"M");
}
MAX_MEMORY:默认情况下分配给JVM的最大内存空间,总内存四分之一
TOTAL_MEMORY:默认情况下除了伸缩区之外的可用内存空间
MAX_MEMORY = 1796.0M
TOTAL_MEMORY = 123.0M
FREE_MEMORY = 120.38259887695312M
在整个分配给JVM使用的堆内存之中,TTOTAL表示用户最大可用,而MAX-TOTAL才表示伸缩区。每一块内存都存在一个伸缩区概念,这会造成下面的情况出现:
如果可用内存空间不足,那么会判断是否伸缩区有空间,有就会开辟伸缩区的空间。那么这就会产生开辟和回收的操作部分,进而会产生性能下降问题。
怎么解决呢?
取消伸缩区的概念
如果现在取消掉伸缩区的概念,初始化内存就设置成最大的可用内存空间,这样就可以实现JVM的性能调整,避免了重复的内存的控制操作,可以提升代码的执行速度。
-Xms:设置初始分配大小,默认为物理内存的“1/64
-Xmx:最大分配内存,默认为物理内存的“1/4”
可以看到默认配置,是“15/64”的内存分配给伸缩区。如果想修改内存的大小(可以使用单位:K、M、G),在本地环境需要考虑到两类情况:
-
IDE修改
-Xms1g -Xmx1g
MAX_MEMORY = 981.5M TOTAL_MEMORY = 981.5M FREE_MEMORY = 971.2599716186523M
可以看到运行结果中,最大分配内存和初始分配内存一样了,这样就取消了伸缩区的概念。
其实,最好是分配内存设置成这样,电脑有64G,保留4G够其他用途,60G分配给Java
-
Java运行修改
java -Xmx1g -Xms1g 类名
在上表中还有一个GC处理详情的查看的参数:-XX:+PrintGCDetails,通过此操作可以详细取得GC处理中的分析过程。
范例:编写一个程序查看GCpublic static void main(String[] args) { String str="hello"; while(true){ str+=str+new java.util.Random(9999999); str.intern(); //入池 } 报的异常:java.lang.OutOfMemoryError: Java heap space
运行结果分析
- 年轻代的处理
[GC (Allocation Failure) 分配失败,意味着当前年轻代没有空间了 [PSYoungGen: 3913K->486K(4608K)] 3913K->1366K(15872K), 0.0024512 secs] [Times: user=0.05 sys=0.00, real=0.00 secs]
-
老年代的处理
[Full GC (Allocation Failure)此时老年代分配内存失败 [PSYoungGen: 32K->0K(4608K)] [ParOldGen: 6439K->6436K(11264K)] 6471K->6436K(15872K), [Metaspace: 3456K->3456K(1056768K)], 0.0088875 secs] [Times: user=0.05 sys=0.00, real=0.01 secs]
-
显示出每一块内存空间的内存使用情况
Heap PSYoungGen total 2560K, used 122K eden space 2048K, 5% used from space 512K, 0% used to space 1536K, 0% used ParOldGen total 11264K, used 6416K object space 11264K, 56% used Metaspace used 3488K, capacity 4496K, committed 4864K, reserved 1056768K class space used 379K, capacity 388K, committed 512K, reserved 1048576K
-
- 年轻代的处理
监控程序
上面堆内存空间使用情况,实际上只能给开发人员查看,运维看不懂。如果想让运维看,必须使用一些监控程序。Java有两类监控程序,JDK的bin目录下
-
jmap.exe (可以在Linux上运行)
在命令行执行后,会将整个进程的内存的使用情况整合列出
-
jvisualvm.exe (图形化,不能在linux上看)
启动后,可以看到IDEA执行的项目
修改IDEA运行参数 -Xms5G -Xmx5G -XX:+PrintGCDetails ,并启动
监视可以看到内存占用情况、垃圾回收
线程可以看到程序中运行的线程
最后,看一个面试题:你们项目之中是如何对Java(JVM)进行调优的?在堆内存会存在伸缩区的概念,默认情况下最大可用内存是整体的“1/4”,默认初始使用的内存是“1/64”, 这时只需要避免伸缩区频繁变更就可以提高性能。具体做法:在运行时设置“-Xmx”、“-Xms”大小一样。
最最后,提醒大家一句:性能的调优不是一蹴而就的,项目本身写的非常烂,再怎么调优提升也不大。除此之外,你的电脑内存很大,你希望充分发挥JVM的性能,你可以这样调优。同时,这样调优也是最基本的调优。