精华内容
下载资源
问答
  • 本文将会列出可能导致GC停顿时间长的一些原因和解决方案。1. 对象创建的速度过高如果应用创建对象的速度非常高,随之而来的就是GC频率也会变快,然后会导致GC的停顿时间变长。所以说,优化代码以降低对象的创建速率...

    应用运行过程中是不希望出现长时间的GC停顿的,因为这会影响服务的可用性,导致用户体验变差,甚至会严重损害一些关键的应用程序。本文将会列出可能导致GC停顿时间长的一些原因和解决方案。

    1. 对象创建的速度过高

    如果应用创建对象的速度非常高,随之而来的就是GC频率也会变快,然后会导致GC的停顿时间变长。所以说,优化代码以降低对象的创建速率是降低GC停顿时间最有效的方法。这可能是一件非常耗时的事情,但是却非常值得去做。

    可以使用JProfiler, YourKit, JVisualVM这样的性能监控工具来帮助优化对象的创建速度,这些工具会分析出:应用到底创建了哪些对象?对象创建的速度是多少?这些对象占用了多少内存空间?是谁创建的这些对象?所谓擒贼先擒王,因此首先要考虑优化那些占用内存最多的对象。

    2. Young区过小

    如果Young过小,对象就会过早的晋升到Old区,Old区的垃圾回收一般比Young区会花费更多的时间,因此,可以通过增大Young区来有效的降低长时间GC停顿。可以用下面两个JVM参数来设置Young区的大小:

    -Xmn: 设置Young区所占的字节数

    -XX:NewRatio: 设置Old区和Young区的比例,比如说,-XX:NewRatio=3也就是说Old区和Young区的比例是3:1,Young区占整个堆的1/4,如果堆是2G,那么Young区就是0.5G。

    3. 选择合适的GC算法

    GC算法是影响GC停顿时间的一个非常重要的因素,除非你是个GC方面的专家或者你的团队中有这方面的专家可以调优GC的设置达到最优的停顿时间,否则我建议选择使用G1收集器,因为G1是自动调优的,你只需要设置一个停顿时间的目标就可以了,比如: -XX:MaxGCPauseMillis=200。这个例子设置了最大停顿时间的目标是200ms,JVM会尽最大努力来满足这个目标。如果你已经使用了G1但是还是出现了长时间的GC停顿,那么请继续阅读本文。

    4. 进程被交换(Swap)出内存

    有时候由于系统内存不足,操作系统会把你的应用从内存中交换出去。Swap是非常耗时的,因为需要访问磁盘,相对于访问物理内存来说要慢得多的多。我认为生产环境下的应用是不应该被Swap出内存的。当发生进程Swap的时候,GC停顿时间也会变长。

    下面是从stackoverflow上引用的一个脚本,它能够列出被Swap出内存的进程,要确保你的应用没有被Swap出内存。

    #!/bin/bash

    # Get current swap usage for all running processes

    # Erik Ljungstrom 27/05/2011

    # Modified by Mikko Rantalainen 2012-08-09

    # Pipe the output to "sort -nk3" to get sorted output

    # Modified by Marc Methot 2014-09-18

    # removed the need for sudo

    SUM=0

    OVERALL=0

    for DIR in `find /proc/ -maxdepth 1 -type d -regex "^/proc/[0-9]+"`

    do

    PID=`echo $DIR | cut -d / -f 3`

    PROGNAME=`ps -p $PID -o comm --no-headers`

    for SWAP in `grep VmSwap $DIR/status 2>/dev/null | awk '{ print $2 }'`

    do

    let SUM=$SUM+$SWAP

    done

    if (( $SUM > 0 )); then

    echo "PID=$PID swapped $SUM KB ($PROGNAME)"

    fi

    let OVERALL=$OVERALL+$SUM

    SUM=0

    done

    echo "Overall swap used: $OVERALL KB"

    如果很不幸你的应用被Swap了,你需要:

    给机器增加内存

    减少机器上运行的进程数,以释放更多的内存

    减少应用分配的内存(不推荐,可能会引起其他问题)

    5. GC线程数过少

    GC日志中的每一个GC事件都会打印user、sys、real time,比如:

    [Times: user=25.56 sys=0.35, real=20.48 secs]

    如果GC日志中,real time并不是明显比user time小,这就说明GC线程数是不够的,这就需要增加GC线程了。假如说,user time是25秒,GC线程数是5,那么real time大概是5左右才是正常的(25/5=5)。

    注意:GC线程过多会占用大量的系统CPU,从而会影响应用能使用的CPU资源,因此增加GC线程之前一定要做好测试才可以。

    6. IO负载重

    如果系统的IO负载很重(大量的文件读写)也会导致GC停顿时间过长。这些IO读写不一定是你的应用引起的,可能是机器上其他的进程导致的,但是这仍然会导致你的应用的停顿时间变长。这里有个文章详细的说明了这种情况:https://engineering.linkedin.com/blog/2016/02/eliminating-large-jvm-gc-pauses-caused-by-background-io-traffic。 当IO负载很重的时候,real time会明显比user time长,比如:

    [Times: user=0.20 sys=0.01, real=18.45 secs]

    如果发生了这种情况,可以这么办:

    如果是你的应用导致的,优化你的代码

    如果是别的进程导致的,把它杀掉或者迁走

    把你的应用迁到一个IO负载小的机器上

    tip:如何来监控IO负载?在linux上可以用sar命令来监控IO的负载:sar -d -p 1,这个命令每隔一秒会打印一次每秒的读写数量。这里有sar的详细的用法:https://www.linuxtechi.com/generate-cpu-memory-io-report-sar-command/

    7. 手动调用了System.gc()

    当调用了System.gc()或者是Runtime.getRuntime().gc()以后,就会导致FullGC。FullGC的过程当中,整个JVM是暂停的(所有的应用都被暂停掉)。

    System.gc()可能是以下几种情况产生的:

    应用的程序员手动调用了System.gc()

    应用引用的三方库或者框架甚至是应用服务器可能调用了System.gc()

    可能是由外部使用了JMX的工具触发,比如:JVisualVM。

    如果你的应用使用了RMI,RMI会每隔一段时间调用一次System.gc(),这个时间间隔是可以设置的:

    – Dsun.rmi.dgc.server.gcInterval=n

    – Dsun.rmi.dgc.client.gcInterval=n

    要评估一下,是否真的有必要明确调用System.gc()。如果没有必要,就不要调用。同时,你也可以通过给JVM传递‘-XX:+DisableExplicitGC‘参数来禁用掉System.gc()。关于System.gc()的问题和解决方案可以参考:https://blog.gceasy.io/2016/11/22/system-gc/

    8. 堆内存过大

    堆内存过大也会导致GC停顿时间过长,如果堆内存过大,那么堆中就会累计过多的垃圾,当发生FullGC要回收所有的垃圾的时候,就会花费更多的时间。如果你的JVM的堆内存有18G,可以考虑分成3个6G的JVM实例,堆内存小会降低GC的停顿时间。 注意:在应用以上任何一种策略之前,都需要做好测试,这些策略对你可能都不适用,如果使用不当可能带来负面效果。

    9. GC任务分配不均

    就算有多个GC线程,线程之间的任务分配可能也不是均衡的,这个可能有很多种原因:

    扫描大的线性的数据结构目前是无法并行的。

    有些GC事件只发生在单个线程上,比如CMS中的‘concurrent mode failure’。如果你碰巧使用的CMS,可以使用-XX:+CMSScavengeBeforeRemark 这个参数,它可以让多个GC线程之间任务分配的更平均。

    展开全文
  • servlet解决线程安全问题的操作1:设定局部变量 性能好2:方法加同步(第一个线程没有使用完方法,第2个线程不能进来),性能差servle的生命周期创建对象init初始化servlet方法request请求 和response 响应destroy方法...

    servlet解决线程安全问题的操作

    1:设定局部变量 性能好

    2:方法加同步(第一个线程没有使用完方法,第2个线程不能进来),性能差

    servle的生命周期

    创建对象

    init初始化

    servlet方法request请求 和response 响应

    destroy方法销毁

    gc回收

    servlet基本配置

    需要注意2点

    1:里面的name要和servlet中的name必须一样

    2:里面的url-pattern里面的必须要加(/)

    都是通过反射找到对象

    1

    HelloWorld

    /HelloWorld全路径

    2

    HelloWorld

    /HelloWorld/*只要满足第一个一样后面目录乱输入都可以

    3

    HelloWorld

    *.jsp以后缀名jsp就可以查询到

    查找顺序:1--2--3

    优先级一般的判定方式:范围小的优先级最高,范围大的优先级低

    如果一个请求可以匹配多个目录,容器会选择最长的目录匹配

    mali

    123456@qq.com

    servlet3.0新特性

    1:annotation注解支持

    2:模块化编程

    3:servlet异步处理

    4:异步Listener

    5:文件上传api简化

    tomcat7.0.5以上版本才支持servlet3.0

    servletContext的应用上下文

    1:属于整个web程序 不管他怎么样,在这个过程中只能才生一个对象,直到web程序关闭

    2:可以访问到web程序资源的本地输入流

    3:把资源的虚拟路径换位物理路径 使用getRealPath()方法

    4:记录时间日志

    5:绑定一个对象在整个web应用程序中共享

    tomcat对web-inf里面的资源都是受保护的

    重定向:调用sendRedirect()方法,重定向的作用就是跳转页面和跳转servlet

    response响应可以响应2种格式

    1:普通文本格式

    2:2进制格式

    展开全文
  • 关于Java VisualVm添加VisualGC插件显示不支持的问题的解决办法 1.修改远程服务器java设置 找到jdk下的/jre/lib/security/java.policy文件,打开此文件 在文件末尾的 }; 前添加permission java.security.All...

    关于Java VisualVm添加VisualGC插件显示不支持的问题的解决办法

    1.修改远程服务器上java设置
    找到jdk下的/jre/lib/security/java.policy文件,打开此文件
    在文件末尾的 }; 前添加
    permission java.security.AllPermission;后保存。

    2.在jdk/bin目录下运行命令窗口输入
    jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=192.168.2.85 -p 2030运行即可。

    3.本地启动VisualVM,因为在配置JMX时已经添加过服务器节点,如果配置正确,通常VisualVM会自动检测到jstatd连接并添加节点。

    展开全文
  • 前言,线上的是一台java服务,启动参数如下所示: -Xmx5g -Xms5g -Xmn3g -Xss256k -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:...

      前言,线上的是一台java服务,启动参数如下所示:

    -Xmx5g -Xms5g -Xmn3g -Xss256k -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -XX:+PrintClassHistogram -XX:PretenureSizeThreshold=2145728 -XX:ErrorFile=$LOG_DIR/systemError.log -Xloggc:$LOG_DIR/gc.log

    这个服务已经在线上运行了很久并没有出现什么问题.

    1月9号下午的时候,我们的同事突然告诉我,线上的一台服务器在疯狂的FullGC,如图所示:

    可以看到,FullGC的次数简直就是瞎眼可见地增长,比MinorGc的频率还快,但是同时每次GC完并没有释放任何内存空间。我们的启动参数又指定了老年代使用内存超过70%触发CMS收集器的GC,所以这就形成了一个死循环:GC -->清理完空间并没有变化 -->继续GC。而这时FGC的此时已经超过了42000多次,就算按照2S一次来算,这种死循环也已经运行了超过20个小时!

    于是,第一时间我们想到是发生了内存泄露,就赶紧先把当前堆栈的信息dump出来,使用命令:


         jmap -dump:format=b,live,file=/data/temp/wtf.hprof 21234
     

    将dump出来的文件下载下来,在本地用JProfiler工具分析:

    可以看到几乎所有的内存都是被char[]占用了,于是继续查看char[]的引用链:

    几乎所有的char[]都是被BufferRecycle(红色标注部分)直接引用的,而最终引用链都指向了线程池中的一个线程(蓝色标准部分)。图中我们看到这些cahr[]非常的大,达到了524KB,而像这样的char[]还有将近2600多个!所占用的内存大小约1.3G,是造成这次事故的根本原因。于是我们就开始逐步分析,先分析为什么BufferRecycle会有这么多char数组。于是我们翻看了Jackson源码,最终发现了问题所在:

     在Jackson将对象转Json时,会默认的从BufferRecyclers中获取BufferRecycle,而BufferRecycle里面存的就是Json字符串的char数组,代码可以去查看com.fasterxml.jackson.databind.ObjectMapper 的writeValueAsString()方法的第一句。
    解释一下就是说,默认情况下Jackson在转Json时,会在BufferRecycle类中创建char[]用于存储字符串。而且会将这个BufferRecycle绑定到当前线程上(通过SoftReference),当下一次转Json时,就可以直接获取到BufferRecycle中的char[],这样可以减少char[]的创建。

    到这里,我们就已经明确了出现问题的原因:我们在代码中使用了线程池,但是线程池大小设置的不合理,两个静态线程池的大小加起来是4000个。而每个线程都会至少调用一次jackson的转json方法(用于打印日志或者存储数据之类),这样就使得这4000个线程池上都绑定了这样一个BufferRecycle,而线程池的线程是可以复用的,不会被销毁的(项目中所有的线程池都是静态的,不会调用shutdown方法),就这样导致了内存泄露。

    那为什么我们的服务没有崩溃呢?也是由于以下两点原因:

    1. 线程的数量虽然大,但是也还有限制,在当时的情况下已经达到了巅峰,已经不会再增长了。

    2.这些char[]其实是通过软引用(SoftReference)关联到线程上的,在GC的时候是允许被回收掉的,但是软引用的回收有自己的算法(跟空闲内存,上次GC时间,系统参数SoftRefLRUPolicyMSPerMB相关,clock - timestamp > freespace * SoftRefLRUPolicyMSPerMB 当返回为true的时候才会被回收),所以即便在GC的时候也会有软引用不能被清理掉。这就导致了每次GC释放的空间实在有限。

    清楚了原因也就明确了解决办法:

    1.修改线程池大小,将原来的4000个改为了较为合理的100个(关于合理的线程池大小可以去网上搜)
    2.防止jackson使用缓存,添加配置:

    objectMapper.getFactory().configure(JsonFactory.Feature.USE_THREAD_LOCAL_FOR_BUFFER_RECYCLING,false);

     3.立即清理软引用,在启动参数中添加,这样在GC的时候可以立即将软引用清除掉

    +XX:SoftRefLRUPolicyMSPerMB=0

    至此,就将线上的问题排查出来并解决了。感慨一下,在问题刚报出来的时候,关于问题出现的原因完全没有头绪,对于JProfiler这样的工具使用的也不是很得手,导致虽然排查了一晚上但是并没有得出什么结论。写这篇博客也是为了做个记录,也希望能帮到几个看到这篇博客的人。虽然问题出现的情况和原因千奇百态,但是排查问题的思路还是大同小异的:
    先把堆栈信息dump出来,通过工具查看,找到其中异常的点,查看它的引用链,分析其中的原因,最终得出结论。

    展开全文
  • 一、问题现象今天A系统上线时,B系统报了可用率问题。经查看日志,发现是B系统调用的A系统接口线程池被打满,而且报警确实是刚刚上线...1、检查该服务器GC情况。发现在这个时间点,发生了fullgc但是发生fgc的时候,...
  • 登录服务器查询JAVA进程heap的概要信息,使用命令:jmap –heap 3772,结果如下图所示: 从上图可见,老年代已使用99%,这时JVM会不停的GCGC时会Stop-the-world,当Stop-the-world发生时,除了GC所需的线程以外,...
  • java.lang.OutOfMemoryError: GC overhead limit exceeded 原因:GC垃圾回收机、说白了就是你的服务器不够牛逼。...解决方案:GC调优:springBoot项目:java.lang.OutOfMemoryError: GC overhead limit exceeded
  • JAVA程序最爽的地方是它的GC机制,开发人员不需要关注内存申请和回收问题。同时,JAVA程序最头疼的地方也是它的GC机制,...吞吐量降低问题不大,横向扩展几台服务器就能解决问题了啦。 ZGC目标 如下图所示,ZGC的目标主
  • 另人头痛的java.lang.OutOfMemoryError:GC overhead limit exceeded 2019-11-21 星期六、一大早一个钉钉的语音通知工单系统挂了。 马上洗漱完跑到公司,打开远程服务器看了一下报错信息 ???内存溢出 首先重启...
  • java web服务器cpu占用过高的处理

    千次阅读 2013-06-20 09:42:34
    ava程序 cup使用率过高,会导致程序运行...频繁的GC.或者有大量的线程。 算法太复杂或者太多 数据库连接的资源未释放或未关闭, 数据库connection过于频繁。 1,使用jps查找出java进程的pid,如3707
  • 阿里云服务器echo $JAVA_HOME 发现没有设置,但确实是装了open-jdk,whereis java也找不到安装路径, 无法使用jstat命令查看JVM 解决:find / -name *jstat* 找到jstat脚本路径,./jstat -gc XXX进行查看,或自己...
  • 下面是Windows下Tomcat服务器日志中出现的异常: 这种问题的异常解释是什么,我就不再描述了,百度有各种解说,只说一下在我的运行环境下怎么解决这个问题,不让问题出现,功能正常运行起来的方法。项目是一个...
  • 记一次jvm疯狂gc导致CPU飙高的问题解决

    万次阅读 多人点赞 2018-10-09 19:42:50
    记录一次java虚拟机CPU飙高的异常处理 线上web服务器不时的出现非常卡的情况,登录服务器top命令发现服务器CPU非常的高, 重启tomcat之后CPU恢复正常,半天或者一天之后又会偶现同样的问题。 解决问题首先要找到...
  • 服务器日志,提示java.lang.OutOfMemoryError: Java heap space,妥了,这是妥妥的代码有问题啊,脸真疼,查找吧! 查找原因: 1、查看gc状态:jstat -gcutilpid1000 400多次gc。。。,老年代和元数据区都都95%...
  • 今天做一个上传zip进行解压写入服务器,发现写入后无法对上传的ZIP进行删除,即使手动删除也不可以。总是提示被java的jvm占用。 首先怀疑的是某个流没有关闭,但是仔细检查还是什么都关闭了,顺序也是正确的。 ...
  • 我连接了实验室的服务器,linux的,然后运行java程序后弹出错误"Exception in thread “main” java.lang.OutOfMemoryError: GC overhead limit exceeded",我去网上找解决办法,但是在我的目录下找不到tomcat的...
  • 在linux系统下长时间进行性能测试,连续几次发生服务器假死无法连接上的情况,无奈只能重启服务器。在测试路径下发现hs_err_pid17285.log文件,打开文件查看其主要内容如下: # There is insufficient memory for ...
  • 而且原有的client并没有得到释放,虽说javagc,那也是变量没有被引用的情况下才能进行,所以我在写服务器的时候,觉得有点成就感的就是改写了客户端连接服务端的代码,也就是说解决同一个客户端重连接n次的情况,...
  • 服务器架构为:Nginx+resin+memcached+db一、故障原因1、服务器负载高(1)访问量突增(2)代码逻辑问题(3)部分服务失效(ATS,DB,MC......)PS:Linux服务器负载一般在2以下。2、Direct Buffer MemoryDirect Buffer Memory指...
  • 暑假期间在个人服务器上部署springcloud项目。出现了服务莫名其妙会挂掉一两个的问题,重新启动挂掉的服务之后又会出现其他服务挂掉的情况,查看启动日志也并没有发现有异常抛出。令人费解的是所有的服务都是通过...
  • 一 后台服务器问题排查步骤 java后台服务故障排除网络与硬件故障外;可能出现以下问题: 1),CPU过高:例如gc频繁,代码循环逻辑,高并发; 2),内存过高:例如频繁创建对象,内存泄露等这里会有俩种情况,一种报oom,一种...
  • 1.top 查看load free空间还很大 应该不是GC导致的分析下面的进程,发现java进程占用了100%的CPU2.查找java进程下面的哪个线程占用CPU高ps -ef|grep java 获取PID 4381top -H -p 4381通过这个命令发现有一个线程占用...
  • GC问题及相关学习

    2019-05-13 09:07:04
    情景描述:工作中在调用接口时后台服务器gc错误,即 java.lang.OutOfMemoryError 于是一同搜索学习,发现是因为调用接口时会在控制台输出很多消息(比如将量级的JSON数据打印查看等),导致JVM虚拟机运行内存太小...
  • 作者:未完成交响曲发现异常首先通过我们内部搭建的日志平台发现我们线上环境一个java应用有大量的http接口请求超时,登录linux服务器查看网络环境没有问题,判断是应用自身运行异常,重启应用后发现异常还在,开始...
  • 背景前一段时间遇到一种情况,服务器经常宕机,而且没有规律性,查看GC日志发生了out of memory,是堆溢出导致的,分析了一下堆的dump文件,发现在发生OOM时创建了大量的String对象。最后对照时间点,发现宕机的时候...
  • 背景前一段时间遇到一种情况,服务器经常宕机,而且没有规律性,查看GC日志发生了out of memory,是堆溢出导致的,分析了一下堆的dump文件,发现在发生OOM时创建了大量的String对象。最后对照时间点,发现宕机的时候...
  • 背景前一段时间遇到一种情况,服务器经常宕机,而且没有规律性,查看GC日志发生了out of memory,是堆溢出导致的,分析了一下堆的dump文件,发现在发生OOM时创建了大量的String对象。最后对照时间点,发现宕机的时候...
  • 注意:此参考解决方案只是... 前一段时间遇到一种情况,服务器经常宕机,而且没有规律性,查看GC日志发生了out of memory,是堆溢出导致的,分析了一下堆的dump文件,发现在发生OOM时创建了大量的String对象。最...
  • java.lang.OutOfMemoryErro

    2019-09-26 17:47:46
    服务器fineReport 的tomcat下运行多个定时填报任务 重启tomcat时出现java.lang.OutOfMemoryError:GC overhead limit exceeded 错误 解决办法: 1、增加参数,-XX:-UseGCOverheadLimit 2、增...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 142
精华内容 56
关键字:

java服务器解决gc

java 订阅