背景起因:
记起以前的另一次也是关于内存的调优分享下
 
有个系统平时运行非常稳定运行(没经历过大并发考验),然而在一次活动后,人数并发一上来后,系统开始卡。
我按经验开始调优,在每个关键步骤的加入如下代码耗时统计进行压测:
 
long startTime = System.currentTimeMillis();
 callRpc();   //这里比如调用RPC伪代码,当然还在插入数据库,中间件地方都加入统计
 long costTime = (System.currentTimeMillis() - startTime); 
 //统计600毫秒以上耗时
if (costTime > 600) { 
logger.warning("callRpc cost time:" + costTime); 
}
 
然后去grep日志, 最后神奇的发现各个地方都有超过600毫秒的地方...
然后各种定位的误导...
 
当然最终是解决了,原因是由于程序里使用了大对象导致
细分析,即使这种情况深研究也是分很多情况的
 
 
 
问题重现:
原因分析:

由于系统中使用了大对象,当并发来临,内存讲被吃紧,将有可能引起如下三种情况

第一种情况,系统内存够用(JVM内存未使用到SWAP内存),但JVM内存不够,最终导致JVM的频繁垃圾回收(FGC),严重影响性能 (stop the word)

第二种情况,系统内存不够,把JVM堆部分用到了SWAP,那么此时的垃圾回收需要把SWAP的内存换回到系统物理内存再进行JVM的垃圾回收。最大影响,导致每次GC的时间变得很久

第三种情况,  物理内存不够用, 大量JVM的堆内存被交换到SWAP后,垃圾回收时,把SWAP内存换回物理内存,但SWAP的内存又不会立即回, 此时可以观察到垃圾回收同时swap使用的内存会变大(其它部分内存要交换到SWAP里)

 
准备:
ubuntu 1G  4核
先关闭SWAP虚拟空间 sudo swapoff -a
 
java version "1.7.0_101"
apache-tomcat-8.5.9
设置好Tomcat的JVM内存:
JAVA_OPTS="-Xmx500m -Xms500m -Xmn200m -Xss228k -XX:+UseConcMarkSweepGC -XX:+UseParNewGC"
 
apache-jmeter-2.13 用于模拟HTTP请求压测,都是100条线程并发进行压测
 
 
 
模拟代码如下
 
/**
 * 模拟当系统中使用大对象时,对JVM造成的影响
 *
 * @author 包子(何锦彬). 2017.01.07
 * @QQ 277803242
 */
@WebServlet("/Test")
public class Test extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private Logger logger = Logger.getLogger(Test.class.getName());

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // use java heap 10m
        byte[] bts = new byte[1024 * 1024 * 10];// 代码段1
        long startTime = System.currentTimeMillis();
        // deal
        try {
            // 模拟业务花费时间
            Thread.sleep(500);
        } catch (InterruptedException e) {
        }

        // 理论上这里输出500附近
        long costTime = (System.currentTimeMillis() - startTime);
        if (costTime > 600) {
            logger.warning("cost time:" + costTime);
        }

        Writer out = response.getWriter();
        out.append("ok");
    }
 
 
先模拟正常的情况:
先注释掉"代码段1", 1W个请求下来,基本耗时都在500,一切正常,返回都是在500毫秒附近
 
垃圾回收情况,只发生了1次YGC,所以系统正常稳定...
 
 
 
模拟第一种情况:
放开“代码段1”,让每次请求都去堆内存申请10m的堆空间,同样是1W个请求,返回的平均值已经接近了2S
 
垃圾回收情况来看, 已经发生了1966次的FGC了, 在上面耗时158秒
 
 
 
模拟第二种情况:
把系统的SWAP打开,打开2G的SWAP,swapon -a
 
调大JVM参数,到1G,让JVM用到部分SWAP的空间
 
此时再让每次请求都去堆内存申请10m的堆空间,同样是1W个请求,性能已经低于第二种情况
 
 
垃圾回收来看,回收次数是1766次,比第二种情况发生的次数还要少, 但FGC耗费的时间已经是212秒,(虽然多了200m内存也没差距这么大,更精确看年轻代一样的内存,耗时也远超过)远超过第二种情况了
 
 
 
模拟第三种情况:
这种情况和我上一篇提到的类似,如果系统内存不够用时,系统将KIIL掉内存
 
 
总结:
 
1,频繁垃圾回收(FGC),会严重影响性能。而且会导致用统计耗时去寻找瓶颈出现失误
2,如果JVM堆用到了SWAP分区,将会严重影响到JVM的性能。故评估给JAVA分配内存时不要统计SWAP部分
3,SWAP分区开启可以有效防止进程因为内存问题而被系统杀掉
 
 
持续更新留言问题,解答疑问
 

欢迎关注我的公众号,专注重现各种线上的BUG

 

随机推荐

  1. android基础开发之WebView

    WebView 是android平台沟通 http & H5 页面的桥梁. 但是google对这块的表述不是很清晰,而且SDK里面基本看不到源码,只有一个接口而已. 传送:http://dev ...

  2. chromium for android v34 2dcanvas硬件渲染实现分析

    这篇接着上一篇2dcanvas硬件绘制,分析保存绘制结果的texture被合成到on screen framebuffer上的过程. 1.webkit为canvas元素相应的render树节点Rend ...

  3. POJ3258-River Hopscotch-二分

    这个题就是排排坐,二分就可以了... River Hopscotch Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 1325 ...

  4. java线程池与五种常用线程池策略使用与解析

    背景:面试中会要求对5中线程池作分析.所以要熟知线程池的运行细节,如CachedThreadPool会引发oom吗? java线程池与五种常用线程池策略使用与解析 可选择的阻塞队列BlockingQu ...

  5. Python_时间复杂度概念

    时间频度:一个算法中的语句执行次数称为语句频度或时间频度,记为T(n)(T代表次数,n代表问题规模) 时间复杂度:呈现时间频度的变化规律,记为T(n)=O(f(n)) 指数时间:一个问题求解所需的执行 ...

  6. c# txt内存映射技术总结

    对于大文件操作,readline 的方式读取文档,那操作起来跟蜗牛爬一样的慢了, 于是使用内存映射技术, 参考微软的这个使用方法说明 https://msdn.microsoft.com/zh-cn/ ...

  7. php常用的安全过滤函数

    目录结构 ①常用的安全函数有哪些: ②这些函数的作用: ③函数的用法: ④举例说明: ⑤参考资料: 由于越来越多的项目开始使用框架,所以,很多的程序员也不在关心安全的问题!因为框架已经帮我们几乎完美的 ...

  8. Cross-Site Script

    Cross-Site Script(跨站脚本)XSS 整理于<浅析XSS(Cross Site Script)漏洞原理>   了解XSS的触发条件就先得从HTML(超文本标记语言)开始,我 ...

  9. android studio 简介 (上)

    自从android官方宣布不再提供eclipse adt的更新之后,android studio的推进速度超乎想象得快,不管是github上的源码分享,还是stackoverflow上的问题提问,几乎 ...

  10. PytorchZerotoAll学习笔记(四)--线性回归

    线性回归 # 导入 torch.torch.autograd的Variable模块import torch from torch.autograd import Variable # 生成需要回归需要 ...