JVM----JVM调优

工具

  jvisualvm.exe:JDK自带,jdk1.8.0_131in

方法区内存溢出异常

  jdk1.8和1.7自带的hotspot虚拟机的差异了。从jdk1.8开始,自带的hostspot虚拟机取消了过去的永久区,而新增了metaspace区,从功能上看,metaspace可以认为和永久区类似,其最主要的功用也是存放类元数据,但实际的机制则有较大的不同。首先,metaspace默认的最大值是整个机器的物理内存大小,所以metaspace不断扩张会导致java程序侵占系统可用内存,最终系统没有可用的内存;而永久区则有固定的默认大小,不会扩张到整个机器的可用内存。当分配的内存耗尽时,两者均会触发full gc,但不同的是永久区在full gc时,以堆内存回收时类似的机制去回收永久区中的类元数据(Class对象),只要是根引用无法到达的对象就可以回收掉,而metaspace判断类元数据是否可以回收,是根据加载这些类元数据的Classloader是否可以回收来判断的,只要Classloader不能回收,通过其加载的类元数据就不会被回收。

  方法区溢出也是一种常见的内存溢出异常,一个类如果要被垃圾收集器回收,要达成的条件是比较苛刻的。在经常运行时生成大量动态类的应用场景里,就应该特别关注这些类的回收状况,这类场景除了之前提到的程序使用了CGLib字节码增强和动态语言外,常见的还有:大量JSP或动态产生JSP文件的应用(JSP第一次运行时需要编译为Java类)、基于OSGI的应用(即使是同一个类文件,被不同的加载器加载也会被视为不同的类)。

  使用jdk的动态代理不会造成方法区内存溢出,使用cglib动态代理,如果设置了enhancer.setUseCache(false)【默认是true】,就有可能造成方法区溢出,原因是不使用缓存,无限创建动态代理,生成class对象。

内存溢出解决情况

  可以加参数,如果发送内存溢出自动生成dump文件,然后用jvisualvm.exe,查看dump文件,检查那个对象占用的内存最多,通过业务代码分析原因

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:srvdump

  

设置GC日志

参考:https://blog.csdn.net/goldenfish1919/article/details/93997132

-XX:+PrintGCDetails 
-XX:+PrintGCDateStamps
#%t会给文件名添加时间戳后缀,格式是YYYY-MM-DD_HH-MM-SS
-Xloggc:/home/GCEASY/gc-%t.log
-XX:+UseGCLogFileRotation
#最多是5个日志文件
-XX:NumberOfGCLogFiles=5
#每个日志文件大小是20M
-XX:GCLogFileSize=20M

PS-PO垃圾收集器的日志分析

2021-01-10T21:52:59.360+0800: 1.366: [Full GC (Ergonomics) [PSYoungGen: 15872K(年轻代回收前)->13154K(年轻代回收后)(17920K)(总大小)] [ParOldGen: 511K->511K(512K)] (如果没有就是没有回收老年代)16383K(整个堆回收前)->13665K(整个堆回收后)(18432K)(总大小), [Metaspace: 3590K->3590K(1056768K)], 0.1673693 secs] [Times: user=0.30 sys=0.00, real=0.17 secs]

GC垃圾收集器

https://blog.csdn.net/varyall/article/details/81634272?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.control

GC优化归纳了两个目的:

  • 一个是将转移到老年代的对象数量降到最少
  • 另一个是减少Full GC的执行时间

频繁GC的检查方法

1、硬件本身设置的内存少,内存不够

2、扩展内存后,频繁GC,并且内存空间不释放(对象无法回收)

排查(简单):

1、jps 或者ps -ef|grep java 或者top :查看正在运行的程序,top可以查看进程占用cpu和内存,可以top监听一下程序,如果一个程序内存一直在上升,不释放,那可能就有问题了

2、jmap -histo [PID] head -20:查看比较占内存的对象以及数量以及占用空间大小,可以多执行几次

  实际当中用不了,如果实际当中生产服务器内存10g,一个jmap命令,可能服务就要停好几个小时。

  一般使用JVM加参数,-XX:+HeapDumpOnOutOfMemoryError,参数表示当JVM发生OOM时,自动生成DUMP文件。-XX:HeapDumpPath=${目录}参数表示生成DUMP文件的路径,也可以指定文件名称,例如:-XX:HeapDumpPath=${目录}/java_heapdump.hprof。如果不指定文件名,默认为:java_<pid>_<date>_<time>_heapDump.hprof。

3、查看业务逻辑,为啥这个对象一直生成,并且无法回收

附加

查看线程情况

  top -Hp pid:查看进程中不同的线程占用内存空间(-H 显示线程信息,-p指定pid)

  jstack pid :该进程所有的线程列举出来,通过线程调用栈排查问题。

  https://www.cnblogs.com/shengulong/p/8513652.html

tomcat出现

Unloading class sun.reflect.GeneratedMethodAccessor的原因

  这表示方法区已经满了,现在在这卸载方法区里面的类,这是正常的现象,说明大量使用反射生成的class被jvm正确回收了。 

  在大量使用发射、动态代理、cglib等框架比如Spring、hibernate等,都需要虚拟机具备类卸载的功能,以保证方法区不会溢出。如果限制类卸载功能及限制 PermSize大小,相信方法区很快就会溢出。所以那些“奇怪信息”也属于正常的输出。另外也可以通过调大 PermSize的值已保证有足够的空间来装载这些类信息,这样,“这些信息”就可能不会输出了。

原文地址:https://www.cnblogs.com/yanxiaoge/p/14254831.html