qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

如何用好LoadRunner中的检查点

如何用好LoadRunner中的检查点
转自:领测软件测试网[http://www.ltesting.net]
原文链接:http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0120/203946.html

如何用好LoadRunner中的检查点LR中检查点有两种:图片和文字。 常用检查点函数如下: 1)web_find()函数用于从 HTML 页中搜索指定的文本字符串; 2)web_reg_find()函数注册一个请求,以在下一个操作函数(如 web_url)检索到的HTML网页上搜  LR中检查点有两种:图片和文字。

  常用检查点函数如下:

 

  1)web_find()函数用于从 HTML 页中搜索指定的文本字符串;

  2)web_reg_find()函数注册一个请求,以在下一个操作函数(如 web_url)检索到的HTML网页上搜索指定的文本字符串;

  3)web_image_check()函数用于从HTML页面中查找指定的图片;

  4)web_global_verfication()属于注册函数,注册一个在web页面中搜索文本字符串的请求,与web_reg_find只在下一个Action函数中执行搜索不同的是它在之后所有的Action类函数中执行搜索指定的文本字符串;


  下面分别介绍以上函数的用法:

  1、web_find()函数参数举例:


  web_find("web_find","RighOf=a","LeftOf=b","What=name",LAST);

 

  参数解释:"web_find"定义该查找函数的名称;“LeftOf”和“RighOf=”用来定义查找字符的左右边界;“What=”定义查找内容;

  例如上述参数举例中的意思就是在页面中查找左边界为b,右边界为a,内容为name的信息;


  使用该函数注意事项:该函数是在查找页面中的内容,所以要放在要查找的内容的后面;该函数只能在基于HTML模式录制的脚本中进行查找

  注意事项:使用该函数时,要在Vuser->Run-Tme Settings中更改下设置


  勾选Enable Image and text check

 

  系统默认是不勾选该选项的。

 

  2、web_reg_find()函数参数举例:


  web_reg_find("Search=Body","SaveCount=ddd","Test=aaa",LAST);

  参数解释: Search用来定义查找范围,SaveCount定义查找计数变量名称,该参数可以记录在缓存中查找内容出现的次数,可以使用该值,来判断要查找的内容是否被找到;

 

  例如上述参数举例中的意思就是Body中查找内容为aaa的信息,并将出现次数记录在变量ddd中;

  【代码一:web_reg_find("Text=Payment Details",LAST);

 

  代码思路:1.“Payment Details” 为你要检查的文本;

  2. 脚本执行到此处,若在页面上找到了这几个字符串,那脚本继续执行下去;若没有找到,脚本将在此报错并且结束。】

  【代码二:web_reg_find("Text=Payment Details", "SaveCount=para_count", LAST); //check 的函数

  web_submit_form("reservations.pl_2", //要check的页面的录制时的代码

  "Snapshot=t22.inf",


  ITEMDATA,

  "Name=outboundFlight", "Value=003;0;06/23/2007", ENDITEM,

  "Name=reserveFlights.x", "Value=61", ENDITEM,


  "Name=reserveFlights.y", "Value=2", ENDITEM,

  LAST);

 

  if (atoi(lr_eval_string("{para_count}"))>0) //验证是否找到了页面上的要检查的字符串

  lr_output_message("we find the string!");

  else

 

  lr_output_message("sorry,don't find the string!");

  代码思路:1.“Payment Details” 为你要检查的文本;

  2. 脚本执行到此处,不管页面上是否存在你要检查的字符串,脚本都不会报错,而是执行下去。

  3. 此段代码将找到的你要检查的字符串的个数,存为一个参数。 然后在页面代码的后面,通过检查这个参数的值是否大于0,来判断是否找到了你所要检查的字符串。】

  【代码三:


  A. web_reg_find("Text=Payment Detdils", "Fail=NotFound",LAST);或

  B. web_reg_find("Text=Payment Detdils", "Fail=Found",LAST);


  代码思路:


  1.“Payment Details” 为你要检查的文本;


  2. 若是A代码:脚本执行到此处,若没有找到check的字符串,脚本将FAIL, 并且停止执行下去。反之,则一直执行下去。

  3. 若是B代码:脚本执行到此处,若找到check的字符串,脚本将FAIL, 并且停止执行下去。反之,则一直执行下去】

 

  使用该函数注意事项:该函数是在缓存中查找相应的内容,所以要放在查找内容之前;通常情况下写在如下六个函数之前:Web_castom_request(); web_image(); web_link(); web_submit_data(); web_submit_form(); web_url();

  使用技巧:在该函数的参数中有个“SaveCount”,该参数可以记录在缓存中查找内容出现的次数,我们可以使用该值,来判断要查找的内容是否被找到,下面举个例子来说明:(引用LR的帮助中的例子)


  // Run the Web Tours sample

 

  web_url("MercuryWebTours",

  "URL=http://localhost/MercuryWebTours/",

  "Resource=0",

 

  "RecContentType=text/html",

  "Referer=",

 

  "Snapshot=t1.inf",

 

  "Mode=HTML",

 

  LAST);

 

  // Set up check for successful login by looking for "Welcome"

  web_reg_find("Text=Welcome",

  "SaveCount=Welcome_Count",


  LAST);

  // Now log in

  web_submit_form("login.pl",

  "Snapshot=t2.inf",

转自:领测软件测试网[http://www.ltesting.net]


ITEMDATA, Name=username, Value=jojo, ENDITEM, Name=password, Value=bean, ENDITEM, Name=login.x, Value=35, ENDITEM, Name=login.y, Value=14, ENDITEM, LAST); // Check result if (atoi(lr_eval_string({Wel
  ITEMDATA,

  "Name=username", "Value=jojo", ENDITEM,

  Name=password", "Value=bean", ENDITEM,

  "Name=login.x", "Value=35", ENDITEM,

 

  "Name=login.y", "Value=14", ENDITEM,


  LAST);


  // Check result

  if (atoi(lr_eval_string("{Welcome_Count}")) > 0){ //判断如果Welcome字符串出现次数大于0


  lr_output_message("Log on successful."); }//在日志中输出Log on successful

  else{ //如果出现次数小于等于

  lr_error_message("Log on failed"); //在日志中输出Log on failed


  return(0); }


  我觉得这个方法非常有用,我们可以举一反三,应用到我们实际的项目

  注:在录制过程中添加的检查点,用到的函数是web_reg_find(),且参数只有“Text=”

  3、web_image_check()函数参数说明:

  web_image_check("web_image_check","Alt=","Src=",LAST);

 

  参数解释:“Alt”和“Src”的值直接取该图片在网页源代码中相应参数的值;

 

  注意事项:使用该函数时,要在Vuser->Run-Tme Settings中勾选Enable Image and text check,具体操作请看web_find()中的注意事项。


  经过测试,该函数用到查找内容前面或后面,都不影响查找结果。

 

  举例说明(脚本)

  该脚本记录的是登陆系统后退出的操作,在脚本中用到atoi()函数和lr_eval_string(”{SaveCount定义的变量}”)两个函数结合使用,判断查找内容出现的次数是否大于0,若大于0,则输入登录成功的信息。

 

  vuser_init()


  {

  web_url("xjcost",


  "URL=http://gczj-server8:9205/xjcost/",

 

  "Resource=0",

  "RecContentType=text/html",


  "Referer=",

  "Snapshot=t1.inf",


  "Mode=HTML",

 

  EXTRARES,


  "Url=jsp/images/index/index.swf", ENDITEM,

 

  "Url=jsp/images/index/xxfb2.gif", ENDITEM,

 

  "Url=jsp/images/index/ywpt2.gif", ENDITEM,

 

  LAST);

 

  web_url("userAction.struts",

 

  "URL=http://gczj-server8:9205/xjcost/userAction.struts?actionType=reLogin",


  "Resource=0",

  "RecContentType=text/html",

 

  "Referer=",

  "Snapshot=t2.inf",

  "Mode=HTML",


  LAST);

  return 0;

  }

  Action()

 

  {

  lr_start_transaction("Log_on");


  lr_rendezvous("Log_on");

 

  web_add_cookie("userAccount=admin; DOMAIN=gczj-server8");

 

  web_reg_find("Text=欢迎您",

  "SaveCount=欢迎您_Count",


  LAST);

 

  web_image_check("web_image_check",

  "Src=/xjcost/jsp/images/index1/edit_01.gif",

  LAST);

 

  web_submit_data("userLogin.struts",

  "Action=http://gczj-server8:9205/xjcost/userLogin.struts?actionType=userLogin",


  "Method=POST",

  "RecContentType=text/html",

  "Referer=http://gczj-server8:9205/xjcost/userAction.struts?actionType=reLogin",

 

  "Snapshot=t3.inf",

  "Mode=HTML",

 

  ITEMDATA,

  "Name=userAccount", "Value=admin", ENDITEM,

  "Name=pwd", "Value=1111", ENDITEM,


  EXTRARES,

  "Url=jsp/images/index1/edit_01a.gif", "Referer=http://gczj-server8:9205/xjcost/userLogin.struts?actionType=userLogin", ENDITEM,

  LAST);


  web_find("web_find",

  "What=欢迎您",

  LAST);

 

  lr_end_transaction("Log_on",LR_AUTO);

  //检查是否登录成功


  //如果“欢迎您”这个字符出现次数大于0,输出“Log on successfully!”

  if(atoi(lr_eval_string("{欢迎您_Count}"))>0)


  lr_output_message("Log on successfully!");


  else

  lr_error_message("Log on failed!");


  return 0;

 

  return 0;

  }

  //atoi()函数的作用是将一个ASCII字符串转换为整型

  //lr_eval_string()函数作用是取得参数值,将字符串变量中的参数值替换为当前的参数值并将这个字符串返回

 

  vuser_end()


  {

  lr_think_time(4);

 

  web_url("userAction.struts_2",


  "URL=http://gczj-server8:9205/xjcost/userAction.struts?actionType=reLogin",

 

  "Resource=0",


  "RecContentType=text/html",

 

  "Referer=",


转自:领测软件测试网[http://www.ltesting.net]
原文链接:http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0120/203946_2.html

 

Snapshot=t4.inf, Mode=HTML, LAST); return 0; } Global.h: #ifndef _GLOBALS_H #define _GLOBALS_H //-------------------------------------------------------------------- // Include Files #include lrun.h
  "Snapshot=t4.inf",

  "Mode=HTML",

  LAST);

 

  return 0;

 

  }

 

  Global.h:


  #ifndef _GLOBALS_H

  #define _GLOBALS_H

  //--------------------------------------------------------------------

  // Include Files

 

  #include "lrun.h"

 

  #include "web_api.h"

  #include "lrw_custom_body.h"

  //--------------------------------------------------------------------

  // Global Variables

 

  #endif // _GLOBALS_H


  Replay Log常见信息说明

 

  1、web_find()和web_image_check()函数的日志信息(这两个日志信息实际上是一样的,只是输出的函数名和参数不同)

 

  1)信息1Action.c(22): Verification checks not enabled. web_image_check is skipped. See the 'Run-time settings/Preferences/Checks'


  [MsgId: MMSG-27197]

 

  Action.c(22): web_image_check was successful


  [MsgId: MMSG-26392]


  出现该信息,说明没有勾选Enable Image and text check

 

  2)信息2Action.c(22): "web_image_check" succeeded (1 occurrence(s) found. Alt="", Src="/xjcost/jsp/images/index1/edit_01.gif")

  [MsgId: MMSG-27192]


  Action.c(22): web_image_check was successful

 

  [MsgId: MMSG-26392]

 

  出现该信息,说明检查点设置成功,且已经查找到信息

  3)信息3Action.c(22): Error -27191: "web_image_check" failed (0 occurrence(s) found. Alt="", Src="/xjcost/jsp/images/index1/edit_1.gif")

  [MsgId: MERR-27191]


  Action.c(22): web_image_check highest severity level was "ERROR"

 

  [MsgId: MMSG-26391]

  出现该信息,说明要查找的内容没有找到。这时依次尝试以下操作:

 

  (1)检查参数的信息是否写错;

  (2)如果是web_find(),检查函数的位置是否在要查找内容的后面;

 

  (3)如果是web_image_check(),查看该图片的源代码,看其是否是这个页面上的图片,很可能是图片选择错误,即所选图片不属于该页面。


  2、web_reg_find()函数的日志信息


  1)信息1Action.c(15): Registering web_reg_find was successful

 

  [MsgId: MMSG-26390]

  出现该信息,说明内容已查找到


  2)信息2Action.c(27): Error -26366: "Text=ABC" not found for web_reg_find

  [MsgId: MERR-26366]

 

  Action.c(27): web_submit_data("userLogin.struts") highest severity level was "ERROR", 18364 body bytes, 918 header bytes, 13 chunking overhead bytes

  [MsgId: MMSG-26387]

 

  该信息在replay log页面是红色显示的,说明没有找到内容,出现此情况尝试以下两个操作:

  (1)参数的信息是否正确;

 

  (2)查看该函数是否在查找内容的前面。


  插入函数的方法:

  1、 手工写入,在需要插入函数的位置手工写入该函数;

 

  2、 光标停留在要插入函数的位置,在INSERT菜单中,选择new step,在列表中选择或查找要插入的函数,根据提示填写必要的参数;


  3、 在tree view模式下,在树状菜单中选中要插入函数的位置,右键,选择insert after或insert before,根据提示填写必要的参数;

  总结:


  1、 这两个函数函数类型不同,WEB_FIND是普通函数,WEB_REG_FIND是注册函数;

  2、 WEB_FIND使用时必须开启内容检查选项,而WEB_REG_FIND则不没有此限制;

 

  3、 WEB_FIND只能用在基于HTML模式录制的脚本中,而WEB_REG_FIND没有此限制;


  4、 WEB_FIND是在返回的页面中进行内容查找,WEB_REG_FIND是在缓存中进行查找;

  5、 WEB_FIND在执行效率上不如WEB_REG_FIND;


转自:领测软件测试网[http://www.ltesting.net]
原文链接:http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0120/203946_3.html


原文链接:http://www.ltesting.net/ceshi/ceshijishu/rjcsgj/mercury/loadrunner/2012/0120/203946.html

posted @ 2012-01-25 22:18 顺其自然EVO 阅读(2733) | 评论 (0)编辑 收藏

Linux系统下完成Windows的开发环境替换

 当下有很多的人都在Windows下进行开发工作,在Windows下搭建相关的开发环境并且使用各种开发工具进行工作。其实更多的专业开发人员会选择Linux操作系统作为他们大的系统环境。理由很简单,Linux运行起来更快,更灵活,更加安全。

  Windows下的开发环境以及软件

  Visual Studio 2010

  Visual Studio 是微软公司推出的开发环境。是目前最流行的 Windows 平台应用程序开发环境。Visual Studio 可以用来创建 Windows 平台下的 Windows 应用程序和网络应用程序,也可以用来创建网络服务、智能设备应用程序和 Office 插件。

  在VisualStudio2010中,微软用全新的WPF技术重新打造了它的编辑器,借助WPF的强大功能,新的编辑器可以实现很多以前VisualStudio2008的IDE根本无法想象的功能,比如代码的无级缩放,多窗口即时更新,文档地图,代码的自动产生等等,这些新的IDE特性都会极大地提高程序员的开发效率。

  Linux系统下的开发环境架设与工具

  Eclipse,GCC,make,Perl,Python,Tcl/Tk各种语言都有。我的机器里安装了Eclipse3.2及GCC等。在Linux下的java开发一点问题都没有。tomcat、myeclipse、svn等一系例软件都有Linux版本,很是方便。

  Tomcat

  Tomcat服务器是一个免费的开放源代码的Web应用服务器,Tomcat很受广大程序员的喜欢,因为它运行时占用的系统资源小,扩展性好,支持负载平衡与邮件服务等开发应用系统常用的功能;而且它还在不断的改进和完善中,任何一个感兴趣的程序员都可以更改它或在其中加入新的功能。

  大多数商业化的J2EE服务器都提供一个功能强大的管理界面,且大都采用易于理解的Web应用界面。Tomcat按照自己的方式,同样提供一个成熟的管理工具,并且丝毫不逊于那些商业化的竞争对手。Tomcat的Admin Web Application最初在4.1版本时出现,当时的功能包括管理context、data source、user和group等。

SVN

  SVN用户管理系统是一套基于PHP+MYSQL运行环境的web程序,由Maia支持、Xuejiang开发,版权归Maia和Xuejiang所有。程序的设计目的主要是帮助配置管理员方便、高效地管理Subversion系统(基于apache)的用户及权限;至于配置库创建、目录创建、复制等配置库操作则暂不在本程序考虑范围内,因为这些操作Subversion本身已可高效完成,实无须再由第三方程序来画蛇添足。

  Eclipse

  Eclipse 能够更好的自动完成提示信息,对于关联文件和路径的设置可以使程序员在编码过程中获得整个项目的清晰视图和方向指引。改进的文件链接功能可以更直接 的控制和管理项目中的文件和文件夹;管理Linux/Unix文件的权限属性。

  据统计,太阳神所有项目的代码有3300万行之多,由来自44家公司的大约500名Eclipse.org社区自愿者贡献的,需要注意的是,虽然这39个项目是统一时间发布,但并不意味着它们是统一的,每个项目都是Eclipse.org的独立开源项目,它们都有自己的项目负责人,贡献者和开发计划,同期发布的目的是为了给大家提供一个可预见的开发周期。

  其实对于开发者来说,Linux系统环境更适合工作。上面介绍的Linux环境下开发工具与开发环境希望对大家会有所借鉴。




posted @ 2012-01-20 09:59 顺其自然EVO 阅读(302) | 评论 (0)编辑 收藏

分析TOP语句放到表值函数外,效率异常低下的原因

 SQLSERVER的表值函数是SQLSERVER 2005以来的新特性,由于它使用比较方便,就像一个单独的表一样,在我们的系统中大量使用。有一个获取客户数据的SQLSERVER 表值函数,如果使用管理员登录,这个函数会返回150W行记录,大概需要30秒左右,但如果将TOP语句放到表值函数外,效率异常低下,需要约3分钟:

select top 20  * from GetFrame_CustomerSerch('admin','1')

  下面是该存储过程的定义:

  1. ALTER FUNCTION [dbo].[GetFrame_CustomerSerch]  
  2. (      
  3.     -- Add the parameters for the function here 
  4.     @WorkNo varchar(38)  
  5.     ,@SerchChar varchar(500)  
  6. )  
  7. RETURNS TABLE   
  8. AS 
  9. RETURN   
  10. (  
  11.     -- Add the SELECT statement with parameter references here 
  12.     select a.GUID,a.CustomerName,a.CustomerIDcard,a.CustomerPhone,a.CustomerMobile from 
  13.     (  
  14.    --具体子查询略 
  15.     )  
  16.     ) a union all 
  17.     select b.GUID,b.CustomerName,b.CustomerIDcard,b.CustomerPhone,b.CustomerMobile from WFT_ManagerCollectUsers a left join WFT_Customer b on a.FundAccount=b.FundAccount  
  18.     --where a.WorkNo=@WorkNo 
  19.     WHERE a.WorkNo IN 
  20.     (  
  21. --具体子查询略 
  22.     )  
  23.     )

  这个语句放在PDF.NET数据开发框架的SQL-MAP文件中,开始还以为是框架引起的,将这个语句直接在查询分析器中查询,仍然很慢。

  将GetFrame_CustomerSerch 中的SQL语句提取出来,直接加上Top查询,只需要6秒,快了N倍:

  1. declare @WorkNo varchar(38)  
  2. declare @SerchChar varchar(500)  
  3. set @WorkNo='admin' 
  4. set @SerchChar='1' 
  5. select top 20 a.GUID,a.CustomerName,a.CustomerIDcard,a.CustomerPhone,a.CustomerMobile from 
  6.  (  
  7.   --具体子查询略 
  8.  )  
  9.  ) a union all 
  10.  select b.GUID,b.CustomerName,b.CustomerIDcard,b.CustomerPhone,b.CustomerMobile from WFT_ManagerCollectUsers a left join WFT_Customer b on a.FundAccount=b.FundAccount  
  11.    
  12.  WHERE a.WorkNo IN 
  13.  (  
  14.  --具体子查询略 
  15.  )

  为什么会有这么大的差异?

  我分析可能有如下原因:

  1、在表值函数外使用Top或者其它条件,SQLSERVER 的查询优化器无法针对此查询进行优化,比如先返回所有记录,然后再在临时表中选取前面的20条记录;

  2、虽说该表值函数使用了“表变量”,它是内存中的,但如果这个“表”结果很大,很有可能内存放不下(并非还有物理内存就会将结果放到物理内存中,数据库自己还会有保留的,会给其它查询预留一定的内存空间),使用虚拟内存,而虚拟内存实际上就是磁盘页面文件,当记录太多就会发生频繁的页面交换,从而导致这个查询效率非常低。

  看来,“表值函数”也不是传说中的那么好,不知道大家是怎么认为的。

  最近还遇到一个怪异的问题,有一个存储过程,老是在系统运行1-2天后变得极其缓慢,但重新修改一下又很快了(只是加一个空格之类),不知道大家遇到过没有,什么原因?

posted @ 2012-01-20 09:58 顺其自然EVO 阅读(345) | 评论 (1)编辑 收藏

Swing使用Substance外观包异常问题

     摘要: 问题一:今天更新我的Java版QQ,在网上找到了Substance外观包,效果不错,直接用了,可是设置水印问题时就出现问题,网上有现成的例子JFrame.setDefaultLookAndFeelDecorated(true);  JDialog.setDefaultLookAndFeelDecorated(true);  try  {  &nbs...  阅读全文

posted @ 2012-01-20 09:56 顺其自然EVO 阅读(534) | 评论 (0)编辑 收藏

深入研究Java虚拟机的类加载机制

  说到Java虚拟机的类加载机制,很多朋友第一反应想到的应该就是ClassLoader,我也如此,不过ClassLoader其实只是Java虚拟机加载机制中的一部分,最近在看《深入理解Java虚拟机》,对Java虚拟机的类加载机制有了更深入的了解,不吐不快。

  JVM中类的整个生命周期如下:

  加载=》验证=》准备=》解析=》初始化=》使用=》卸载

  使用和卸载这两个步骤不在今天的讨论范围之内,今天我们将着重讨论一下前5个步骤,也就是JVM中类的整个加载机制。

  1、加载

  类的加载阶段,主要是获取定义此类的二进制字节流,并将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构,最后在Java堆中生成一个代表这个类的java.lang.Class对象作为方法区这些数据的访问入口。

  相对于类加载过程的其他阶段,加载阶段是开发期可控性最强的阶段。我们可以通过定制不通的类加载器,也就是ClassLoader来控制二进制字节流的获取方式。

  关于ClassLoader的介绍,请参照 了解ClassLoader

  2、验证

  验证,准备和解析其实都属于连接阶段,而验证就是连接阶段的第一步。这一阶段主要是为了确保Class文件的字节流中包含的信息复合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

  主要验证过程包括:文件格式验证,元数据验证,字节码验证以及符号引用验证。

  3、准备

  准备阶段正式为类变量分配内存并设置初始值。这里的初始值并不是初始化的值,而是数据类型的默认零值。这里提到的类变量是被static修饰的变量,而不是实例变量。

  关于准备阶段为类变量设置零值的唯一例外就是当这个类变量同时也被final修饰,那么在编译时,就会直接为这个常量赋上目标值。

  4、解析

  解析时虚拟机将常量池中的符号引用替换为直接引用的过程。

  5、初始化

  在准备阶段,变量已经赋过一次系统要求的初始值,在初始化阶段,则是根据程序员通过程序的主观计划区初始化类变量和其他资源。

  Java虚拟机规范规定了有4种情况必须立即对类进行初始化(加载,验证,准备必须在此之前完成)

  1)当使用new关键字实例化对象时,当读取或者设置一个类的静态字段(被final修饰的除外)时,以及当调用一个类的静态方法时,如果类未初始化,则需先初始化。

  2)通过反射机制对类进行调用时,如果类未初始化,则需先初始化。

  3)当初始化一个类时,如果其父类未初始化,先初始化父类

  4)用户指定的执行主类(含main方法的那个类)在虚拟机启动时会先被初始化

  除了上面这4种方式,所有引用类的方式都不会触发初始化,称为被动引用。如:通过子类引用父类的静态字段,不会导致子类初始化;通过数组定义来引用类,不会触发此类的初始化;引用类的静态常量不会触发定义常量的类的初始化,因为常量在编译阶段已经被放到常量池中了。

  总结:

  在上述5个过程当中,验证,准备和解析完全由Java虚拟机主导和控制。只要加载阶段和初始化阶段程序员可以进行控制。在加载阶段可以通过实现自定义的ClassLoader来加载类的二进制流,在初始化阶段程序员则可完全按照需求来为类变量赋值。

posted @ 2012-01-19 11:24 顺其自然EVO 阅读(147) | 评论 (0)编辑 收藏

Java的动态绑定机制

  Java的动态绑定又称为运行时绑定。意思就是说,程序会在运行的时候自动选择调用哪儿个方法。

  一、动态绑定的过程

  例子:

  1. public class Son extends Father  
  2. Son son = new Son();3 son.method();

  1、首先,编译器根据对象的声明类型和方法名,搜索相应类(Son)及其父类(Father)的“方法表”,找出所有访问属性为public的method方法。

  可能存在多个方法名为method的方法,只是参数类型或数量不同。

  2、然后,根据方法的“签名”找出完全匹配的方法。

  方法的名称和参数列表称为方法的签名。

  在Java SE 5.0 以前的版本中,覆盖父类的方法时,要求返回类型必须是一样的。现在子类覆盖父类的方法时,允许其返回类型定义为原始类型的子类型。

  1. public Father getFather(){...} //父类中的方法  
  2. public Son getFather(){...} //子类覆盖父类中的getFather()方法

  3、如果是private、static、final 方法或者是构造器,则编译器明确地知道要调用哪儿个方法,这种调用方式成为“静态调用”。

  4、调用方法。

  如果子类Son中定义了 method() 的方法,则直接调用子类中的相应方法;如果子类Son中没有定义相应的方法,则到其父类中寻找method()方法。

  二、Demo

  1、子类重写父类中的方法,调用子类中的方法

  1. public class Father{  
  2.     public void method(){  
  3.         System.out.println("父类方法:"+this.getClass());  
  4.   }  
  5. }  
  6. public class Son extends Father{  
  7.     public void method(){  
  8.         System.out.println("子类方法"+this.getClass());  
  9. }  
  10. public static void main(String[] args){  
  11.     Father instance = new Son();  
  12.     instance.method();  
  13.     }  
  14. }  
  15. //结果:子类方法:class Son

  2、子类没有重写父类中的方法,所以到父类中寻找相应的方法

  1. public class Father{  
  2.     public void method(){  
  3.         System.out.println("父类方法:"+this.getClass());  
  4.     }  
  5. }  
  6. public class Son extends Father{  
  7.     public static void main(String[] args){  
  8.         Father instance = new Son();  
  9.         instance.method();   
  10.     }  
  11. }  
  12. //结果:父类方法:class Son

  三、动态绑定只是针对对象的方法,对于属性无效。因为属性不能被重写。

  1. public class Father{  
  2.     public String name = "父亲属性";  
  3.     }  
  4. public class Son extends Father{  
  5.     public String name = "孩子属性";  
  6.     public static void main(String[] args){  
  7.         Father instance = new Son();  
  8.         System.out.println(instance.name);  
  9.     }  
  10. }  
  11. //结果:父亲属性

posted @ 2012-01-18 10:59 顺其自然EVO 阅读(206) | 评论 (0)编辑 收藏

Java编码及网络传输中的编码问题

     摘要: Java编码及网络传输中的编码问题 近来试着FTP搜索,遇到编码问题,研究了下。  Java内部的String为Unicode编码,每个字符占两个字节。  Java编解码方法如下:String str = "hi好啊me";  byte[] gbkBytes=str.getBytes("GBK");//将String的Unicode编码转为GBK编...  阅读全文

posted @ 2012-01-17 11:30 顺其自然EVO 阅读(2579) | 评论 (0)编辑 收藏

Java中删除数组中重复元素

这个是一个老问题,但是发现大多数人说的还不够透。小弟就在这里抛砖引玉了,欢迎拍砖.......

  问题:比如我有一个数组(元素个数为0哈),希望添加进去元素不能重复。

  拿到这样一个问题,我可能会快速的写下代码,这里数组用ArrayList.

  1. private static void testListSet(){  
  2.         List<String> arrays = new ArrayList<String>(){  
  3.             @Override 
  4.             public boolean add(String e) {  
  5.                 for(String str:this){  
  6.                     if(str.equals(e)){  
  7.                         System.out.println("add failed !!!  duplicate element");  
  8.                         return false;  
  9.                     }else{  
  10.                         System.out.println("add successed !!!");  
  11.                     }  
  12.                 }  
  13.                 return super.add(e);  
  14.             }  
  15.         };  
  16.                 arrays.add("a");arrays.add("b");arrays.add("c");arrays.add("b");  
  17.         for(String e:arrays)  
  18.             System.out.print(e);  
  19.     }

  这里我什么都不关,只关心在数组添加元素的时候做下判断(当然添加数组元素只用add方法),是否已存在相同元素,如果数组中不存在这个元素,就添加到这个数组中,反之亦然。这样写可能简单,但是面临庞大数组时就显得笨拙:有100000元素的数组天家一个元素,难道要调用100000次equal吗?这里是个基础。

  问题:加入已经有一些元素的数组了,怎么删除这个数组里重复的元素呢?

  大家知道java中集合总的可以分为两大类:List与Set。List类的集合里元素要求有序但可以重复,而Set类的集合里元素要求无序但不能重复。那么这里就可以考虑利用Set这个特性把重复元素删除不就达到目的了,毕竟用系统里已有的算法要优于自己现写的算法吧。

  1. public static void removeDuplicate(List<People> list){  
  2.    HashSet<People> set = new HashSet<People>(list);  
  3.    list.clear();  
  4.    list.addAll(set);  
  5. }  
  6. ivate static People[] ObjData = new People[]{  
  7.     new People(0"a"),new People(1"b"),new People(0"a"),new People(2"a"),new People(3"c"),  
  8. };

  1. public class People{  
  2.     private int id;  
  3.     private String name;  
  4.       
  5.     public People(int id,String name){  
  6.         this.id = id;  
  7.         this.name = name;  
  8.     }  
  9.       
  10.     @Override 
  11.     public String toString() {  
  12.         return ("id = "+id+" , name "+name);  
  13.     }  
  14.       
  15. }

  上面的代码,用了一个自定义的People类,当我添加相同的对象时候(指的是含有相同的数据内容),调用removeDuplicate方法发现这样并不能解决实际问题,仍然存在相同的对象。那么HashSet里是怎么判断像个对象是否相同的呢?打开HashSet源码可以发现:每次往里面添加数据的时候,就必须要调用add方法:

  1.       @Override 
  2.      public boolean add(E object) {  
  3.          return backingMap.put(object, this) == null;  
  4.      }

 这里的backingMap也就是HashSet维护的数据,它用了一个很巧妙的方法,把每次添加的Object当作HashMap里面的KEY,本身HashSet对象当作VALUE。这样就利用了Hashmap里的KEY唯一性,自然而然的HashSet的数据不会重复。但是真正的是否有重复数据,就得看HashMap里的怎么判断两个KEY是否相同。

  1.         @Override public V put(K key, V value) {  
  2. 390         if (key == null) {  
  3. 391             return putValueForNullKey(value);  
  4. 392         }  
  5. 393   
  6. 394         int hash = secondaryHash(key.hashCode());  
  7. 395         HashMapEntry<K, V>[] tab = table;  
  8. 396         int index = hash & (tab.length - 1);  
  9. 397         for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {  
  10. 398             if (e.hash == hash && key.equals(e.key)) {  
  11. 399                 preModify(e);  
  12. 400                 V oldValue = e.value;  
  13. 401                 e.value = value;  
  14. 402                 return oldValue;  
  15. 403             }  
  16. 404         }  
  17. 405   
  18. 406         // No entry for (non-null) key is present; create one  
  19. 407         modCount++;  
  20. 408         if (size++ > threshold) {  
  21. 409             tab = doubleCapacity();  
  22. 410             index = hash & (tab.length - 1);  
  23. 411         }  
  24. 412         addNewEntry(key, value, hash, index);  
  25. 413         return null;  
  26. 414     }

  总的来说,这里实现的思路是:遍历hashmap里的元素,如果元素的hashcode相等(事实上还要对hashcode做一次处理),然后去判断KEY的eqaul方法。如果这两个条件满足,那么就是不同元素。那这里如果数组里的元素类型是自定义的话,要利用Set的机制,那就得自己实现equal与hashmap(这里hashmap算法就不详细介绍了,我也就理解一点)方法了:

  1. public class People{  
  2.     private int id; //  
  3.     private String name;  
  4.       
  5.     public People(int id,String name){  
  6.         this.id = id;  
  7.         this.name = name;  
  8.     }  
  9.       
  10.     @Override 
  11.     public String toString() {  
  12.         return ("id = "+id+" , name "+name);  
  13.     }  
  14.      
  15.     public int getId() {  
  16.         return id;  
  17.     }  
  18.  
  19.     public void setId(int id) {  
  20.         this.id = id;  
  21.     }  
  22.  
  23.     public String getName() {  
  24.         return name;  
  25.     }  
  26.  
  27.     public void setName(String name) {  
  28.         this.name = name;  
  29.     }  
  30.  
  31.     @Override 
  32.     public boolean equals(Object obj) {  
  33.         if(!(obj instanceof People))  
  34.             return false;  
  35.         People o = (People)obj;  
  36.         if(id == o.getId()&&name.equals(o.getName()))  
  37.             return true;  
  38.         else 
  39.             return false;  
  40.     }  
  41.       
  42.     @Override 
  43.     public int hashCode() {  
  44.         // TODO Auto-generated method stub  
  45.         return id;  
  46.         //return super.hashCode();  
  47.     }  
  48. }

  这里在调用removeDuplicate(list)方法就不会出现两个相同的people了。



posted @ 2012-01-16 14:14 顺其自然EVO 阅读(722) | 评论 (0)编辑 收藏

JVM基础:JVM内存组成及分配

 Java内存组成介绍:堆(Heap)和非堆(Non-heap)内存

  按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给 自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法 的代码都在非堆内存中。

  组成图

  ◆ 方法栈&本地方法栈:

  线程创建时产生,方法执行时生成栈帧

  ◆ 方法区

  存储类的元数据信息 常量等

  ◆ 堆

  java代码中所有的new操作

  ◆ native Memory(C heap)

  Direct Bytebuffer JNI Compile GC;

  堆内存分配

  JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指 定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。

组  成详  解

Young Generation

即图中的Eden + From Space + To Space

Eden

存放新生的对象

Survivor Space

有两个,存放每次垃圾回收后存活的对象

Old Generation

Tenured Generation 即图中的Old Space
主要存放应用程序中生命周期长的存活对象

  非堆内存分配

  JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。

组  成详  解

Permanent Generation

保存虚拟机自己的静态(refective)数据
主要存放加载的Class类级别静态对象如class本身,method,field等等
permanent generation空间不足会引发full GC

Code Cache

用于编译和保存本地代码(native code)的内存
JVM内部处理或优化

  JVM内存限制(最大值)

  JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然 可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统 下为2G-3G),而64bit以上的处理器就不会有限制了。

posted @ 2012-01-15 00:56 顺其自然EVO 阅读(174) | 评论 (0)编辑 收藏

JVM调优总结:新一代的垃圾回收算法

垃圾回收的瓶颈

  传统分代垃圾回收方式,已经在一定程度上把垃圾回收给应用带来的负担降到了最小,把应用的吞吐量推到了一个极限。但是他无法解决的一个问题,就是Full GC所带来的应用暂停。在一些对实时性要求很高的应用场景下,GC暂停所带来的请求堆积和请求失败是无法接受的。这类应用可能要求请求的返回时间在几百甚至几十毫秒以内,如果分代垃圾回收方式要达到这个指标,只能把最大堆的设置限制在一个相对较小范围内,但是这样有限制了应用本身的处理能力,同样也是不可接收的。

  分代垃圾回收方式确实也考虑了实时性要求而提供了并发回收器,支持最大暂停时间的设置,但是受限于分代垃圾回收的内存划分模型,其效果也不是很理想。

  为了达到实时性的要求(其实Java语言最初的设计也是在嵌入式系统上的),一种新垃圾回收方式呼之欲出,它既支持短的暂停时间,又支持大的内存空间分配。可以很好的解决传统分代方式带来的问题。

  增量收集的演进

  增量收集的方式在理论上可以解决传统分代方式带来的问题。增量收集把对堆空间划分成一系列内存块,使用时,先使用其中一部分(不会全部用完),垃圾收集时把之前用掉的部分中的存活对象再放到后面没有用的空间中,这样可以实现一直边使用边收集的效果,避免了传统分代方式整个使用完了再暂停的回收的情况。

  当然,传统分代收集方式也提供了并发收集,但是他有一个很致命的地方,就是把整个堆做为一个内存块,这样一方面会造成碎片(无法压缩),另一方面他的每次收集都是对整个堆的收集,无法进行选择,在暂停时间的控制上还是很弱。而增量方式,通过内存空间的分块,恰恰可以解决上面问题。

  Garbage Firest(G1)

  这部分的内容主要参考这里,这篇文章算是对G1算法论文的解读。我也没加什么东西了。

  目标

  从设计目标看G1完全是为了大型应用而准备的。

  支持很大的堆

  高吞吐量

  --支持多CPU和垃圾回收线程

  --在主线程暂停的情况下,使用并行收集

  --在主线程运行的情况下,使用并发收

  实时目标:可配置在N毫秒内最多只占用M毫秒的时间进行垃圾回收当然G1要达到实时性的要求,相对传统的分代回收算法,在性能上会有一些损失。

  算法详解

  G1可谓博采众家之长,力求到达一种完美。他吸取了增量收集优点,把整个堆划分为一个一个等大小的区域(region)。内存的回收和划分都以region为单位;同时,他也吸取了CMS的特点,把这个垃圾回收过程分为几个阶段,分散一个垃圾回收过程;而且,G1也认同分代垃圾回收的思想,认为不同对象的生命周期不同,可以采取不同收集方式,因此,它也支持分代的垃圾回收。为了达到对回收时间的可预计性,G1在扫描了region以后,对其中的活跃对象的大小进行排序,首先会收集那些活跃对象小的region,以便快速回收空间(要复制的活跃对象少了),因为活跃对象小,里面可以认为多数都是垃圾,所以这种方式被称为Garbage First(G1)的垃圾回收算法,即:垃圾优先的回收。

 回收步骤:

  初始标记(Initial Marking)

  G1对于每个region都保存了两个标识用的bitmap,一个为previous marking bitmap,一个为next marking bitmap,bitmap中包含了一个bit的地址信息来指向对象的起始点。

  开始Initial Marking之前,首先并发的清空next marking bitmap,然后停止所有应用线程,并扫描标识出每个region中root可直接访问到的对象,将region中top的值放入next top at mark start(TAMS)中,之后恢复所有应用线程。

  触发这个步骤执行的条件为:

  G1定义了一个JVM Heap大小的百分比的阀值,称为h,另外还有一个H,H的值为(1-h)*Heap Size,目前这个h的值是固定的,后续G1也许会将其改为动态的,根据jvm的运行情况来动态的调整,在分代方式下,G1还定义了一个u以及soft limit,soft limit的值为H-u*Heap Size,当Heap中使用的内存超过了soft limit值时,就会在一次clean up执行完毕后在应用允许的GC暂停时间范围内尽快的执行此步骤;

  在pure方式下,G1将marking与clean up组成一个环,以便clean up能充分的使用marking的信息,当clean up开始回收时,首先回收能够带来最多内存空间的regions,当经过多次的clean up,回收到没多少空间的regions时,G1重新初始化一个新的marking与clean up构成的环。

  并发标记(Concurrent Marking)

  按照之前Initial Marking扫描到的对象进行遍历,以识别这些对象的下层对象的活跃状态,对于在此期间应用线程并发修改的对象的以来关系则记录到remembered set logs中,新创建的对象则放入比top值更高的地址区间中,这些新创建的对象默认状态即为活跃的,同时修改top值。

  最终标记暂停(Final Marking Pause)

  当应用线程的remembered set logs未满时,是不会放入filled RS buffers中的,在这样的情况下,这些remebered set logs中记录的card的修改就会被更新了,因此需要这一步,这一步要做的就是把应用线程中存在的remembered set logs的内容进行处理,并相应的修改remembered sets,这一步需要暂停应用,并行的运行。

  存活对象计算及清除(Live Data Counting and Cleanup)

  值得注意的是,在G1中,并不是说Final Marking Pause执行完了,就肯定执行Cleanup这步的,由于这步需要暂停应用,G1为了能够达到准实时的要求,需要根据用户指定的最大的GC造成的暂停时间来合理的规划什么时候执行Cleanup,另外还有几种情况也是会触发这个步骤的执行的:

  G1采用的是复制方法来进行收集,必须保证每次的”to space”的空间都是够的,因此G1采取的策略是当已经使用的内存空间达到了H时,就执行Cleanup这个步骤;

  对于full-young和partially-young的分代模式的G1而言,则还有情况会触发Cleanup的执行,full-young模式下,G1根据应用可接受的暂停时间、回收young regions需要消耗的时间来估算出一个yound regions的数量值,当JVM中分配对象的young regions的数量达到此值时,Cleanup就会执行;partially-young模式下,则会尽量频繁的在应用可接受的暂停时间范围内执行Cleanup,并最大限度的去执行non-young regions的Cleanup。

  展望

  以后JVM的调优或许跟多需要针对G1算法进行调优了。

posted @ 2012-01-12 10:22 顺其自然EVO 阅读(206) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 343 344 345 346 347 348 349 350 351 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜