发布新日志

  • Java中的String,StringBuilder,StringBuffer三者的区别

    2018-02-26 18:33:53

    这三个类之间的区别主要是在两个方面,即运行速度和线程安全这两方面。

    1. 首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String

      String最慢的原因:

      String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。以下面一段代码为例:

    public class StringTest {
        public static void main(String args[]){
            String str="abc";
            System.out.println(str);
            str=str+"de";
            System.out.println(str);//
        }
    }
    

    如果运行这段代码会发现先输出“abc”,然后又输出“abcde”,好像是str这个对象被更改了,其实,这只是一种假象罢了,JVM对于这几行代码是这样处理的,首先创建一个String对象str,并把“abc”赋值给str,然后在第三行中,其实JVM又创建了一个新的对象也名为str,然后再把原来的str的值和“de”加起来再赋值给新的str,而原来的str就会被JVM的垃圾回收机制(GC)给回收掉了,所以,str实际上并没有被更改,也就是前面说的String对象一旦创建之后就不可更改了。所以,Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。

      而StringBuilder和StringBuffer的对象是变量,对变量进行操作就是直接对该对象进行更改,而不进行创建和回收的操作,所以速度要比String快很多。

    另外,有时候我们会这样对字符串进行赋值:

    1 String str="abc"+"de";
    2 StringBuilder stringBuilder=new StringBuilder().append("abc").append("de");
    3 System.out.println(str);
    4 System.out.println(stringBuilder.toString());

    这样输出结果也是“abcde”和“abcde”,但是String的速度却比StringBuilder的反应速度要快很多,这是因为第1行中的操作和

      String str="abcde";

      是完全一样的,所以会很快,而如果写成下面这种形式

    1 String str1="abc";
    2 String str2="de";
    3 String str=str1+str2;

      那么JVM就会像上面说的那样,不断的创建、回收对象来进行这个操作了。速度就会很慢。

    2. 再来说线程安全

      在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的

      如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。

      3. 总结一下
      String:适用于少量的字符串操作的情况

      StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况

      StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况


     

  • Java基础之int和Integer有什么区别

    2018-02-26 17:46:38

    一、int 是基本类型,直接存数值,进行初始化时int类的变量初始为0。 
    integer是对象,用一个引用指向这个对象,Integer的变量则初始化为null。
    从Java 5开始引入了自动装箱/拆箱机制,使得二者可以相互转换。
    二、自动装箱:将基本数据类型重新转化为对象
    public class Test { public static void main(String[] args) { //声明一个Integer对象 Integer num = 9; //以上的声明就是用到了自动的装箱:解析为:Integer num = new Integer(9); } }
    三、自动拆箱:将对象重新转化为基本数据类型
    public class Test { public static void main(String[] args) { //声明一个Integer对象 Integer num = 9; //进行计算时隐含的有自动拆箱 System.out.print(num--); } }

  • jmeter测试接口--解决参数化取唯一值的问题(用UUID)

    2018-02-23 16:18:45

    一、用时间函数:

    jmeter参数化,而且要取唯一值,可以考虑用时间函数加上其他函数一起:

    1
    {"merchant_id":"615051940310129","biz_code":"1001","order_id":"${__time(,)}${__counter(,)}","order_amt":"100","bg_url":"www.baidu.com","sign":"22A356FF1010B22670417E2107DB4229"}

     但是如果接口的处理能力很快,这个参数还是会存在重复的id;

     

    二、用UUID:

    解决上面的问题,还可以用UUID来作为参数,UUID通常以36字节的字符串表示,示例如下:

    1
    3F2504E0-4F89-11D3-9A0C-0305E82C3301

     

     订单ID多数是数字的,如果不需要“-”,可以去掉。

    如下是分析在jmeter中如何使用:

    1.新建一个事务;

    2.新建一个BeanShell Sampler;

    3.新建一个http请求;

    如下图:

     

    4.在BeanShell Sampler编写UUID的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import java.util.UUID;
     
    UUID uuid1 = UUID.randomUUID();    //获取UID的值
     
    vars.put("order_id",(uuid1.toString()).toUpperCase().replaceAll("-",""));  
     
     //去掉UUID的“-”,再赋值给order_id  运行获取的参数就是:3F2504E04F8911D39A0C0305E82C3301
     
    //vars.put("order_id",(uuid1.toString()).toUpperCase()); 
    查看(3581) 评论(0) 收藏 分享 管理

  • 瓶颈分析

    2018-02-23 10:51:54

    CMS GC知识

    CMS,全称Concurrent Mark and Sweep,用于对年老代进行回收,目标是尽量减少应用的暂停时间,减少full gc发生的机率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代。

    一次CMS至少会给Full GC的次数 + 2,因为Full GC的次数是按照老年代GC时stop the world的次数而定的

    我们可以认为Major GC == Full GC,他们是一个概念,就是针对老年代/永久代进行GC。

    1. 应用系统负载分析:

    服务器负载瓶颈经常表现为,服务器受到的并发压力比较低的情况下,服务器的资源使用率比预期要高,甚至高很多。导致服务器处理能力严重下降,最终有可能导致服务器宕机。实际性能测试工作中,经常会用以下三类资源指标判定是否存在服务器负载瓶颈:

    • CPU使用率
    • 内存使用率
    • Load

    一般cup的使用率应低于50%,如果过高有可能程序的算法耗费太多cpu,或者某些代码块进行不合理的占用。Load值尽量保持在cpuS+2 或者cpuS*2,其中cpu和load一般与并发数成正比。

    • 内存可以通过2种方式来查看:

    1) 当vmstat命令输出的si和so值显示为非0值,则表示剩余可支配的物理内存已经严重不足,需要通过与磁盘交换内容来保持系统的稳定;由于磁盘处理的速度远远小于内存,此时就会出现严重的性能下降;si和so的值越大,表示性能瓶颈越严重。

    2) 用工具监控内存的使用情况,如果出现下图的增长趋势(used曲线呈线性增长),有可能系统内存占满的情况:

    %e6%94%af%e4%bb%98%e5%ae%9d%e7%9a%84%e6%80%a7%e8%83%bd%e6%b5%8b%e8%af%95007

    如果出现内存占用一直上升的趋势,有可能系统一直在创建新的线程,旧的线程没有销毁;或者应用申请了堆外内存,一直没有回收导致内存一直增长。

    3)内存分页监控sar -B 5 10

    输出项说明:
    pgpgin/s:表示每秒从磁盘或swap置换到内存的字节数(KB)
    pgpgout/s:表示每秒从内存置换到磁盘或SWAP的字节数(KB)
    fault/s:每秒钟系统产生的缺页数,即主缺页与次缺页之和。
    majflt/s:每秒钟产生的主缺页数。
    pgfree/s:每秒被放入空闲队列中的页个数。是已经扫描到了的空闲页,扫描的空闲page越大,代表内存空余越大 
    pgscank/s:每秒被kswapd扫描的页个数。
    pgscand/s:每秒直接被扫描的页个数。
    pgsteal/s:每秒钟从cache中被清除来满足内存需要的页个数。
    %vmeff:每秒清除的页(pgsteal)占总扫描页(pgscank+pgscand)的百分比。pgsteal/s 除以( pgscank/s + pgscand/s ),pgsteal/s表示每秒释放的cache((pagecache and swapcache)),这个其实就是cache可以释放的页,当CPU需要的page不在cache中时,需要释放cache中的原来的page,从内存和swap中加载需要的page,pgscank/s表示每秒扫描swap的page , pgscand/s表示每秒扫描内存的page,实际上pgscank/s+pgscand/s就是RAM+SWAP 。当vmeff的值变大时,表示从RAM和Swap中置换到cache的page变多,这就意味着用到swap的机会变多。这个参数用来衡量页面置换效率,  超30% 证明物理内存已经处理不过来。这个值越大,则请求越多,越代表内存有问题。
    4.2 Jvm瓶颈分析

    对于java应用来说,过高的GC频率也会在很大程度上降低应用的性能。即使采用了并发收集的策略,GC产生的停顿时间积累起来也是不可忽略的,特别是出现cmsgc失败,导致fullgc时的场景。下面举几个例子进行说明:

    1. Cmsgc频率过高,当在一段较短的时间区间内,cmsGC值超出预料的大,那么说明该JAVA应用在处理对象的策略上存在着一些问题,即过多过快地创建了长寿命周期的对象,是需要改进的。或者old区大小分配或者回收比例设置得不合理,导致cms频繁触发,下面看一张gc监控图(蓝色线代表cmsgc)
    %e6%94%af%e4%bb%98%e5%ae%9d%e7%9a%84%e6%80%a7%e8%83%bd%e6%b5%8b%e8%af%95008

    由图看出:cmsGC非常频繁,后经分析是因为jvm参数-XX:CMSInitiatingOccupancyFraction设置为15,比例太小导致cms比较频繁,这样可以扩大cmsgc占old区的比例,降低cms频率注。

    调优后的图如下:

    %e6%94%af%e4%bb%98%e5%ae%9d%e7%9a%84%e6%80%a7%e8%83%bd%e6%b5%8b%e8%af%95009

    1. fullgc频繁触发

    当采用cms并发回收算法,当cmsgc回收失败时会导致fullgc:

    %e6%94%af%e4%bb%98%e5%ae%9d%e7%9a%84%e6%80%a7%e8%83%bd%e6%b5%8b%e8%af%95010

    由上图可以看出fullgc的耗时非常长,在6~7s左右,这样会严重影响应用的响应时间。经分析是因为cms比例过大,回收频率较慢导致,调优方式:调小cms的回比例,尽早触发cmsgc,避免触发fullgc。调优后回收情况如下

    %e6%94%af%e4%bb%98%e5%ae%9d%e7%9a%84%e6%80%a7%e8%83%bd%e6%b5%8b%e8%af%95011

    可以看出cmsgc时间缩短了很多,优化后可以大大提高。从上面2个例子看出cms比例不是绝对的,需要根据应用的具体情况来看,比如应用创建的对象存活周期长,且对象较大,可以适当提高cms的回收比例。

    1. 疑似内存泄露,先看下图
    %e6%94%af%e4%bb%98%e5%ae%9d%e7%9a%84%e6%80%a7%e8%83%bd%e6%b5%8b%e8%af%95012

    分析:每次cmsgc没有回收干净,old区呈上升趋势,疑似内存泄露

    最终有可能导致OOM,这种情况就需要dump内存进行分析:

    • 找到oom内存dump文件,具体的文件配置在jvm参数里:
    • -XX:HeapDumpPath=/home/admin/logs

    -XX:ErrorFile=/home/admin/logs/hs_err_pid%p.log

    • 借助工具:MAT,分析内存最大的对象。

    结论

    1. 在单接口压测时,我们用“请求总数/总时长”得到吞吐量;然后再用“吞吐量/平均响应时间”得到实际并发,此举可用来观察系统实际承受的并发;
    2. 在多接口压测时,由于短板效应,同一个流程中的所有接口获得的请求总数和总时长都一样,显然“请求总数/总时长”计算各个子接口的吞吐量不合适,所以改用“并发/平均响应时间”,其中的并发数应在压测工具中埋点统计,不可简单使用工具线程数。
  • JMeter-Java Sampler遇到的问题

    2018-02-22 16:59:12

    当运行main方法进行调试时报错,报错如下:
    Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/jorphan/logging/LoggingManager
        at org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient.<clinit>(AbstractJavaSamplerClient.java:55)
    Caused by: java.lang.ClassNotFoundException: org.apache.jorphan.logging.LoggingManager
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        ... 1 more

    问题在于少加载了依赖包,可以把jmeterhome/ lib下所有jar加载到eclipse环境变量中试试。