qileilove

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

Java 乱码解决

 1、jsp页面的编码方式有两个地方需要设置:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ page contentType="text/html;charset=utf-8"%>

  其中:pageEncoding 指的是jsp文件本身在本地保存时的编码方式。contentType的charset是指服务器发送网页内容给客户端时所使用的编码。

  从第一次访问一个jsp页面开始,到这个页面被发送到客户端,这个Jsp页面要经过三次编码转换:

  第一阶段是jsp编译成.java,它会根据pageEncoding的设定读取jsp,结果是由指定的编码方案翻译成统一的UTF-8 JAVA源码(即.java),如果pageEncoding设定错了,或没有设定,出来的就是中文乱码。

  第二阶段是由JAVAC的JAVA源码至java byteCode的编译,不论JSP编写时候用的是什么编码方案,经过这个阶段的结果全部是UTF-8的encoding的java源码。

  JAVAC用UTF-8的encoding读取java源码,编译成UTF-8 encoding的二进制码(即.class),这是JVM对常数字串在二进制码(java encoding)内表达的规范。

  第三阶段是Tomcat(或其的application container)载入和执行阶段二的来的JAVA二进制码,输出的结果,也就是在客户端见到的,这时隐藏在阶段一和阶段二的参数contentType就发挥了功效

  所以最终的解决方法为:

  在jsp页面设置pageEncoding或者contentType的其中一个为支持中文的编码格式(如utf-8,gbk,gb2312)。因为设置一个的话,另一个默认会和它一样。

  如果两个都设置的话,必须保证两个都是支持中文编码(不一定要一样)。

  最佳建议设置如下:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ page contentType="text/html;charset=utf-8"%>

  2、post方式传值乱码:

  由于post方式传值是通过request存储的,在另一个页面也是通过request.getParameter(String name)来提取信息,所以这种情况下的乱码主要是因为request存储信息的编码设置导致的。post提交时,如果没有设置提交的编码格式,则会以iso8859-1方式进行提交,接受的jsp却以utf-8的方式接受。所以使用如下语句即可得到单个正确的中文字符串:String str = new String(request.getParameter("something").getBytes("ISO-8859-1"),"utf-8") ;

  解决方法:

  在接收页面设置request.setCharacterEncoding("UTF-8")。最好通过过滤器实现每个页面都设置为request.setCharacterEncoding("UTF-8")。

  3、get方式传值乱码:

  get方式传值有两种,一种是表单get传值,另一种是url地址传值(实质上这两种方式都是通过url参数的方式传值)。

  表单方式get传值:

  表单方式get传值的编码过程为,首先浏览器根据页面的charset编码方式对传值进行编码,然后提交至服务器交给tomcat,tomcat对这些信息进行解码时,采用的解码方式是由server.xml文件中的URIEncoding设置决定的,也就是说,当我们使用命令request.getParameter("")获取表单参数值时,得到的字符串,经过了charset的编码和URIEncoding的解码。

 由上所知,只要charset的编码和URIEncoding的解码一致,并且支持中文,就能保证没有乱码。

  设置URIEncoding的方法如下:

  方法一:

  修改$TOMCAT/conf/server.xml文件,在HTTP Connector或者AJP Connector的配置加上URIEncoding="gbk"

<...   maxThreads="150" minSpareThreads="25" maxSpareThreads="75" 
      enableLookups="false" redirectPort="8443" acceptCount="100" 
  connectionTimeout="20000" disableUploadTimeout="true" URIEncoding="gbk" />

  方法二:

  使用useBodyEncodingForURI="true". 这个方法适合你的TOMCAT实例下需要跑多个不同Encoding的程序时。

<...  maxThreads="150" minSpareThreads="25" maxSpareThreads="75" 
       enableLookups="false" redirectPort="8443" acceptCount="100" 
      connectionTimeout="20000" disableUploadTimeout="true" useBodyEncodingForURI="true" />

     enableLookups="false" redirectPort="8443" protocol="AJP/1.3" useBodyEncodingForURI="true" />

  在Tomcat配置中,连接器(HTTP Connector)属性中有一个URIEncoding和

  useBodyEncodingForURI属性,这两个属性设置对URL后的附加参数进行URL解码时该如何选择 字符集编码。URIEncoding用于制定URL后的附加参数的字符集编码,useBodyEncodingForURI 则说明是否采用实体内容的字符集编码设置来替代URIEncoding的设置,也就是说当 useBodyEncodingForURI属性设置为true时ServletRequest.setCharacterEncoding方法设置的字符集编码也影响getParameter等方法对URL地址后的参数进行URL解码的结果。(在/%TomCat_Home%/ conf\server.xml文件中找到 <Connector>标记,然后在后面加上useBodyEncodingForURI=true)

  url方式get传值乱码:

  于这种方式,浏览器不会采用页面的charset方式对URL中的中文进行编码后提交至服务器(IE,FireFox都一样),而是采用系统的GBK转码为ISO-8859-1之后提交至服务器tomcat,所以这个过程为:

  首先,url地址中的中文被从gbk转换成ISO-8859-1,交给tomcat后,又被tomcat根据URLEcoding解码,这种情况,只有把URLEcoding设置为gbk才能在request.getParameter("")时不出现乱码。但是这样就会影响到上面的配置,所以一个好的解决方法是,使用java.net.URLEcoder和URLDecoder对地址中的中文进行手动编码和解码。

  所以一个万全的解决方法为:

  1)所有页面的charset设置为UTF-8。

  2)Tomcat的URIEncoding默认是ISO-8859-1,而我设置为UTF-8,主要是想解决中文命名的文件以及请求以get方式提交有可能出现的乱码问题。

  3)添加过滤器,调用request.setCharacterEncoding("utf-8")方法将request的字符集设定为utf-8,解决请求以post方式提交的乱码问题。

  4)url地址中存在中文参数时,首先对中文参数使用URLEcoder编码为utf-8,然后在request.getParameter("")接收到参数后再使用URLDecoder还原。例如:

  From.jsp页面:

<%String username = "张某某" ; 
     username = URLEncoder.encode(username,"utf-8"); 
     %> 
     <a href="to.jsp?param=<%=username %>">转入</a>

  To.jsp页面

 <%=URLDecoder.decode(request.getParameter("param"),"utf-8")%>

  总之 ,乱码的解决方案如下:

  post传值乱码时,在接收端设置request.setCharacterEncoding("UTF-8")

  get传值或者url乱码时,手动设置接收的参数String str = new String(request.getParameter("something").getBytes("ISO-8859-1"),"utf-8") ;

  由上可见get,post传值在tomcat5中是不一样的

posted @ 2011-12-19 16:48 顺其自然EVO 阅读(1904) | 评论 (0)编辑 收藏

测试人员需要为产品质量负责吗?

 测试人员需要为产品质量负责吗?

  这句话其实可以这样问

  医生需要为病人的病情负责吗?

  答案是肯定的。

  一个产品从测试人员手中走过,测试人员需要对它进行有目的的有效的测试,确保尽早的发现产品内在的缺陷,从而在最短的时间内促使开发人员完成对产品的修复,减少企业因此而将要承受的损失。

  这需要测试人员的责任心。面对一个测试任务,需要的是细心,耐心以及自我的分析。知道成本和效益的关系,了解客户最大的需求,知道面对的这个任务,自己的轻重缓急在哪里,不能磨磨蹭蹭,以至于耽误了最佳的测试时间。

  如果测试产品从测试人员手中流过,却没有被检测出隐含的最大的问题,那么就是测试人员的失职。就如同一个医生面对一个病人,经过一番检查,却没有任何的诊断抑或遗漏了最大的病患。

  但是反过来讲,测试人员不能对产品的任何瑕疵都负责任,不可能为产品的质量去100%买单。测试人员只对测试的质量去买单,只为测试的成果负责。

  测试人员虽然尽心尽力的对产品进行了最为有效的测试,但是因为客户的决定,或者开发人员的推委,导致产品的已发现的重大的问题没有被解决掉。面对这部分,测试人员不需要去负责。

  但是也不要因此就影响了士气。虽然,很多时候,人们总说,一个软件做好了,是开发人员的功劳;做得不好,使测试人员的不是。也有很多人,因为这个原因而离开了测试队伍。因为觉得自己跟“替罪羔羊”一样的无奈和无辜。

  其实,很多时候,任何角落,都有一些前台的和幕后的英雄,并不是站在领奖台上的人才是最光荣的。无论是设计者,开发者还是测试人员,都是软件生命周期中不可或缺的重要组成人员,大家共同的努力才成就了软件的上市以及企业的盈利和良好信誉。每一个都要为自己的存在而感到自豪。自己的地位靠自己的努力来不断的得到证明,自己的能力不需要别人的证明。金子在沙地也是金子,沙子在金堆也总是沙子。如果你觉得自己被轻视了,那么,不要放弃,请你努力!相信吧,自己今天的努力一定会换来你更美好的明天。

  测试人员在面对测试任务之前一定学会思考,从客户,从市场,从软件本身的特点去方方面面的思考,知道自己该如何把握,该怎样策划你的测试用例。该如何更加有效的去发现更有价值的bug。

  很多测试人员都觉得很郁闷,当他们的bug被开发的以不需要修复为由而拒掉。但是这个时候抱怨没有用的。开发人员这样做,你要找到理由。开发人员绝对不会贸贸然把一个可能导致软件崩溃的bug置之不理。如果是这样的bug,那么,可能时间已经不够,修复的风险太大,这个时候你要理解,而且要帮助他们出主意,看看怎样解决才是最好。如果你的bug无足轻重,而还有一大堆的问题你都没有去发掘,那么,坐冷板凳是应该的。这个时候,你能做得最好的事情就是,自己多去想,有效地发现出更多更有效的更重要的bug来。

posted @ 2011-12-16 15:17 顺其自然EVO 阅读(184) | 评论 (0)编辑 收藏

教你使用Linux系统的Shell脚本维护Oracle

  系统管理员与 DBA 之间在职责方面存在差别。但实际上,这种差别通常并不明显。许多 IT 部门雇佣一些可解决数据库级以及操作系统级问题的员工。当然,Oracle 数据库本身使用操作系统资源,并能与其环境紧密交互。

  此外,许多系统管理员和DBA 发现将其工作相关的任务自动化很有必要或比较方便。软件安装、系统资源监视以及系统管理涉及一些重复和容易出错的任务,而自动过程可以比手动过程更好地完成这些任务。

  将这些任务自动化的方法之一是shell 脚本。 Shell 脚本自 Linux 系统安装之初就起着重要作用。启动和关闭系统时就会调用各种脚本。 Oracle 和其他第三方供应商的实用程序也是通过 shell 脚本可调用的。由于这些脚本可以快速开发,因此历来就用它们构建应用程序原型。系统管理员已利用通过 shell 脚本实现的功能提供针对其监视的系统的特定要求和特征定制的解决方案了。

  在本文中,我将介绍 “bash”shell 脚本可以实现的、与在 Linux 平台上安装、运行和维护 Oracle 数据库相关的功能。注意,本文适用于 Linux 脚本初学者或对 Linux 相对陌生的 DBA ;对大多数经验丰富的 Linux 系统管理员则不适用。

  ◆Shell 脚本是什么?

  shell 脚本是一个包含命令序列的文本文件。当运行文件(或脚本)时,将执行该文件中包含的命令。术语 shell 仅指与 Linux 内核通信所使用的特定命令行用户界面。目前有多个不同的 shell ,其中包括 C shell (csh) 、 Korn shell (ksh) 、 Bourne shell (sh) 和 Bourne-Again shell (bash) 。 shell 本身就是一个从文件或终端读取命令、解释这些命令并通常执行其他命令的命令。 Bourne-Again shell 合并了上述其他 shell 的特性,本文就使用该脚本进行演示。

  脚本文件中的第一行可用于指定使用哪个 shell 来运行该脚本。以下是所有脚本示例中包含的第一行的含义:

  #!/bin/bash

  ◆为什么使用 Shell 脚本?

  由于 shell 脚本与 DBA 的工作相关,因此您可能不会马上看到 shell 脚本的价值,这跟您的工作经历有关。如果您以前从未使用过 UNIX 或类似 UNIX 的系统,那么可能会对大量含义晦涩的命令感到一愁莫展。此外,除了作为关系数据库外, Oracle 10 g 还提供了一个用于处理数据库数据的强健平台以及几个用于在数据库外部与操作系统交互的方法。

  但您会发现几个探究 shell 脚本领域的原因,其中包括:

  ● 必须支持已经存在的脚本。

  ● 需要在安装 Oracle 软件前自动设置系统。例如,您可以编写一个脚本来检查 OS 的初始状态并报告安装软件前必须满足的任何前提条件。该脚本还可以创建相关的 OS 用户和组并为用户设置环境变量。

  ● 可以使用正在运行的 Oracle 数据库来执行手动或计划的任务。但在数据库 未 运行时需要运行某些任务。可以使用脚本停止或启动数据库(以及侦听器或相关的数据库进程)。无法从数据库内部启动此类动作。

  ● 您需要一种监视数据库状态(例如,是否正在运行并可进行进程查询)的机制。这样的脚本还可以监视非特定于 Oracle 的其他进程和资源,从而提供系统当前运行情况的更详细信息。

  ● 需要将备份自动化。 Oracle Recovery Manager (RMAN) 是一个用于开发可以在任何平台上运行的备份脚本的实用程序。可以从 shell 脚本中调用 Oracle Recovery Manager 并使用它执行各种备份和恢复活动。

  ● 您可能有一个并非特定于某个数据库的要求。您可能在一台计算机上安装了多个数据库。建议您不要使用单个数据库满足此要求,因为那样会引发潜在的安全性问题。在这些情况下, shell 脚本提供了一种既可以满足此要求又不会将进程与单个数据库关联的方法。

  ◆什么情况下不使用 Shell 脚本?

  Oracle 数据库包含了超出 RDBMS 传统定义的功能。与软件的任何其他部分一样,它使用操作系统提供的资源,但它所“ 看到” 并“ 更改” 其环境的程度远远超过了其他软件。SQL 和 Oracle 的固定视图从数据库内部提供了系统视图,而shell 脚本从数据库外部提供了系统视图。Shell 脚本并不是适用于所有问题的解决方案。

  必须意识到,操作系统的许多方面可以从数据库内部进行监视和修改。可以使用Oracle 的固定视图(带 v$ 前缀的视图)确定计算机的主机名 (v$instance) 或数据库正在其中运行的平台的名称 (v$database) 。还可以通过这种方式确定与数据库相关的文件的位置和其他属性。可以直接从数据库中查询数据文件(v$datafile 、 dba_data_files )、临时文件(v$tempfile 、 dba_temp_files )、重做日志 (v$logfile) 、存档日志 (v$archived_log) 和控制文件 (v$controlfile) 的位置和其他属性。可以通过该视图以及通过查看某些 init.ora 参数(db_recovery_file_dest 、 db_recovery_file_dest_size )确定有关闪回恢复区 ($recovery_file_dest) 的信息。还可以查询进程 (v$process) 和内存(v$sga 、 v$sgastat 等)的状态。有各种内置的 PL/SQL 程序包,并能够创建允许对底层 OS 进行其他访问的Java 和C 数据库对象。

  如果您正在考虑为一个需要大量数据库访问的任务编写脚本,则脚本可能并不是最佳选择。本文的稍后部分将介绍如何使用SQL*Plus 访问数据库,但在很多情况下,使用其他语言可以更好地解决此问题。

posted @ 2011-12-16 15:16 顺其自然EVO 阅读(163) | 评论 (0)编辑 收藏

SQL Server监控系列之调优排错

 使用SQL Server Profile GUI工具还是很多优势,首先是减少了我们监控的复杂性,可以款速的建立监控,在跟踪属性中,可以可以选择MSSQL为我们提供的模版,包括常用的T-SQL、T-SQL Duration、T-SQL Locks模版分别监控当前DB运行的所有查询,所有查询的耗时、所有的锁定状态。

  在跟踪属性 –> 选择事件选择 我们可以选择自己需要的事件,所有的事件在MSDN 都有定义->单击列筛选器 可以自定义过滤,排序噪点干扰因素

(我随便选择了一个耗时 = 500 微妙的过滤条件)

  其他的模版大家可以自己看看MSDN 手册,自己尝试一下:SQL Server 2008 R2 本机 MSDN

  服务器端跟踪和物理方式收集

  SQL Server Profile 只是对一些存储过程的封装,我更倾向于,自己定义常用的脚本,将监控结果保存在本机,用来大量的分析和存档。

  当然涉及4个存储过程,虽然设置过滤的脚本非常麻烦,但是SQL Server Profile 可以利用 文件->导出 可以导出监控脚本意味着,我们不需要编写复杂的T-SQL 脚本,不过还是建议大家熟悉这几个存储过程:

  sp_trace_create 定义跟踪 ,创建的跟踪会在sys.traces查询的到。

  s_trace_setevent 设置监控事件

  sp_trace_setfilter 设置过滤

  sp_trace_setstatus 设置跟踪的状态 常用的是 sp_trace_setstatus @traceid,0 停止功能 、sp_trace_setstatus @traceid,2 移除跟踪,这将导致sys.traces最终查询不到该跟踪

  其实整个跟踪还是比较简单的。我这里有一个常用的脚本:

  用来 监控超过指定秒数 和 数据库 的 批处理和存储过程 语句(超过5MB的文件,会执行ROLLOVER,根据文件名在后面添加类似_1,_2.trc的跟踪结果):

以下是代码片段:
CREATE PROC [dbo].[sp_trace_sql_durtion] @DatabaseName nvarchar(128), @Seconds bigint, @FilePath nvarchar(260) AS BEGIN DECLARE @rc int,@TraceID int,@MaxFileSize bigint; SET @MaxFileSize = 5; EXEC sp_trace_create @TraceID OUTPUT,2,@FilePath,@MaxFileSize,NULL; IF @rc != 0 RETURN; DECLARE @On bit; SET @On = 1; EXEC sp_trace_setevent @TraceID,10,35,@On; EXEC sp_trace_setevent @TraceID,10,1,@On; EXEC sp_trace_setevent @TraceID,10,13,@On; EXEC sp_trace_setevent @TraceID,41,35,@On; EXEC sp_trace_setevent @TraceID,41,1,@On; EXEC sp_trace_setevent @TraceID,41,13,@On; SET @Seconds = @Seconds * 1000000; EXEC sp_trace_setfilter @TraceID,13,0,4,@Seconds; IF @DatabaseName IS NOT NULL EXEC sp_trace_setfilter @TraceID,35,0,0,@DatabaseName EXEC sp_trace_setstatus @TraceID,1 SELECT TraceID = @TraceID; END

  参数非常的明了,数据库名称、执行事件超过多少秒、保存的路径。

  当我们运行这个脚本一段事件以后,可以快速的发现大量耗时的T-SQL,我们可以通过

  SELECT * FROM fn_trace_gettable(N'监控文件路径',1);

  来查看行方式的结果。

  同样的富有创造力的读者可以自己创建监控锁定,监控死锁等方式保存文件,但是我的建议是尽可能的减少噪音,也就是说我们要达到什么目地就在《Microsfot SQL Server 2005 技术内幕: T-SQL 程序设计》 中有一个正则,用来将类似的语句全部组合成,只有参数形式替换具体值的SQL CLR,但是我认为那个正则还有bug,等我空了给大家写一个,自己也能使用的更完善。


 使用SQL Server Profile GUI工具还是很多优势,首先是减少了我们监控的复杂性,可以款速的建立监控,在跟踪属性中,可以可以选择MSSQL为我们提供的模版,包括常用的T-SQL、T-SQL Duration、T-SQL Locks模版分别监控当前DB运行的所有查询,所有查询的耗时、所有的锁定状态。

  在跟踪属性 –> 选择事件选择 我们可以选择自己需要的事件,所有的事件在MSDN 都有定义->单击列筛选器 可以自定义过滤,排序噪点干扰因素

(我随便选择了一个耗时 = 500 微妙的过滤条件)

  其他的模版大家可以自己看看MSDN 手册,自己尝试一下:SQL Server 2008 R2 本机 MSDN

  服务器端跟踪和物理方式收集

  SQL Server Profile 只是对一些存储过程的封装,我更倾向于,自己定义常用的脚本,将监控结果保存在本机,用来大量的分析和存档。

  当然涉及4个存储过程,虽然设置过滤的脚本非常麻烦,但是SQL Server Profile 可以利用 文件->导出 可以导出监控脚本意味着,我们不需要编写复杂的T-SQL 脚本,不过还是建议大家熟悉这几个存储过程:

  sp_trace_create 定义跟踪 ,创建的跟踪会在sys.traces查询的到。

  s_trace_setevent 设置监控事件

  sp_trace_setfilter 设置过滤

  sp_trace_setstatus 设置跟踪的状态 常用的是 sp_trace_setstatus @traceid,0 停止功能 、sp_trace_setstatus @traceid,2 移除跟踪,这将导致sys.traces最终查询不到该跟踪

  其实整个跟踪还是比较简单的。我这里有一个常用的脚本:

  用来 监控超过指定秒数 和 数据库 的 批处理和存储过程 语句(超过5MB的文件,会执行ROLLOVER,根据文件名在后面添加类似_1,_2.trc的跟踪结果):

以下是代码片段:
CREATE PROC [dbo].[sp_trace_sql_durtion] @DatabaseName nvarchar(128), @Seconds bigint, @FilePath nvarchar(260) AS BEGIN DECLARE @rc int,@TraceID int,@MaxFileSize bigint; SET @MaxFileSize = 5; EXEC sp_trace_create @TraceID OUTPUT,2,@FilePath,@MaxFileSize,NULL; IF @rc != 0 RETURN; DECLARE @On bit; SET @On = 1; EXEC sp_trace_setevent @TraceID,10,35,@On; EXEC sp_trace_setevent @TraceID,10,1,@On; EXEC sp_trace_setevent @TraceID,10,13,@On; EXEC sp_trace_setevent @TraceID,41,35,@On; EXEC sp_trace_setevent @TraceID,41,1,@On; EXEC sp_trace_setevent @TraceID,41,13,@On; SET @Seconds = @Seconds * 1000000; EXEC sp_trace_setfilter @TraceID,13,0,4,@Seconds; IF @DatabaseName IS NOT NULL EXEC sp_trace_setfilter @TraceID,35,0,0,@DatabaseName EXEC sp_trace_setstatus @TraceID,1 SELECT TraceID = @TraceID; END

  参数非常的明了,数据库名称、执行事件超过多少秒、保存的路径。

  当我们运行这个脚本一段事件以后,可以快速的发现大量耗时的T-SQL,我们可以通过

  SELECT * FROM fn_trace_gettable(N'监控文件路径',1);

  来查看行方式的结果。

  同样的富有创造力的读者可以自己创建监控锁定,监控死锁等方式保存文件,但是我的建议是尽可能的减少噪音,也就是说我们要达到什么目地就在《Microsfot SQL Server 2005 技术内幕: T-SQL 程序设计》 中有一个正则,用来将类似的语句全部组合成,只有参数形式替换具体值的SQL CLR,但是我认为那个正则还有bug,等我空了给大家写一个,自己也能使用的更完善。

 监控异常

  在上个系列中,讲述了具体的SQL Event抓去的异常,可以及时通知,但是具体的异常信息,并不是特别详细。因此我们可以选择事件中的Error来添加有关T-SQL批处理和SP的所有异常,用于分析,这个跟踪非常有利于我们监控一些异常情况!!!我创建了一个跟踪的脚本,和上面的跟踪事件的脚本一样,超过5MB RollOver。我们要定期的执行这个跟踪,虽然不建议长期开启,但是定期监控处理异常是有利我们系统更加长时间运作的。

以下是代码片段:
CREATE PROC [dbo].[sp_trace_sql_exception] @FilePath nvarchar(260) AS DECLARE @rc int,@TraceID int,@Maxfilesize bigint SET @maxfilesize = 5 EXEC @rc = sp_trace_create @TraceID output, 2, @FilePath, @Maxfilesize, NULL IF (@rc != 0) RETURN; DECLARE @on bit SET @on = 1 EXEC sp_trace_setevent @TraceID, 33, 1, @on EXEC sp_trace_setevent @TraceID, 33, 14, @on EXEC sp_trace_setevent @TraceID, 33, 51, @on EXEC sp_trace_setevent @TraceID, 33, 12, @on EXEC sp_trace_setevent @TraceID, 11, 2, @on EXEC sp_trace_setevent @TraceID, 11, 14, @on EXEC sp_trace_setevent @TraceID, 11, 51, @on EXEC sp_trace_setevent @TraceID, 11, 12, @on EXEC sp_trace_setevent @TraceID, 13, 1, @on EXEC sp_trace_setevent @TraceID, 13, 14, @on EXEC sp_trace_setevent @TraceID, 13, 51, @on EXEC sp_trace_setevent @TraceID, 13, 12, @on DECLARE @intfilter int,@bigintfilter bigint; EXEC sp_trace_setstatus @TraceID, 1 SELECT TraceID=@TraceID GOTO finish ERROR: SELECT ErrorCode=@rc FINISH:

  定期执行吧,同志们,找异常。。。

  默认跟踪和黑盒跟踪

  在sys.traces中的TraceID = 1的跟踪是SQL Server 默认跟踪,这个跟踪比较轻量级,一般监控服务器的启用停止,对象的创建和删除,日志和数据文件自动增长以及其他数据库的变化。(监控那些没事删错了表的人,是最好的,当然前提不要都使用一个帐号!)

  可以通过

以下是代码片段:
EXEC sp_configure 'default trace enabled',0; RECONFIGURE WITH OVERRIDE;

  来关闭默认跟踪。

  黑盒跟踪,就是可以帮助我们诊断数据库没事自个奔了的异常,在MSDN 搜索sp_create_trace的时候应该也发现了

  的选项,那么我们也能创建一个类似的存储过程来快速的创建黑盒跟踪,帮助我们诊断一些异常!

以下是代码片段:
CREATE PROCEDURE sp_trace_blackbox @FilePath nvarchar(260) AS BEGIN DECLARE @TraceID int,@MaxFileSize bigint SET @MaxFileSize = 25; EXEC sp_trace_create @TraceID OUTPUT,8,@FilePath,@MaxFileSize EXEC sp_trace_setstatus @TraceID,1; END

  我这里提供@FilePath = NULL参数,这个默认就保存在SQL Server的数据文件夹中。

  结尾

  这里详细的描述了SQL Server Trace 的各种功能特性,有兴趣的朋友可以深入到MSDN研究监控,我这是也只是一笔带过,也参考了MSDN 和《Microsoft SQL Server 2005调优》那本书,下面的监控可能和大家讲述 DDL触发器监控,C2审核以及SQL Server的事件通知(涉及的Service Broker我会开一个系列和大家详细说说Service Broker),最后的结束可能就是说说2008的数据收集监控

posted @ 2011-12-16 15:02 顺其自然EVO 阅读(192) | 评论 (0)编辑 收藏

Java内存泄露的理解与解决

 Java内存管理机制

  在C++ 语言中,如果需要动态分配一块内存,程序员需要负责这块内存的整个生命周期。从申请分配、到使用、再到最后的释放。这样的过程非常灵活,但是却十分繁琐,程序员很容易由于疏忽而忘记释放内存,从而导致内存的泄露。 Java 语言对内存管理做了自己的优化,这就是垃圾回收机制。 Java 的几乎所有内存对象都是在堆内存上分配(基本数据类型除外),然后由 GC ( garbage collection)负责自动回收不再使用的内存。

  上面是Java 内存管理机制的基本情况。但是如果仅仅理解到这里,我们在实际的项目开发中仍然会遇到内存泄漏的问题。也许有人表示怀疑,既然 Java 的垃圾回收机制能够自动的回收内存,怎么还会出现内存泄漏的情况呢?这个问题,我们需要知道 GC 在什么时候回收内存对象,什么样的内存对象会被 GC 认为是“不再使用”的。

  Java中对内存对象的访问,使用的是引用的方式。在 Java 代码中我们维护一个内存对象的引用变量,通过这个引用变量的值,我们可以访问到对应的内存地址中的内存对象空间。在 Java 程序中,这个引用变量本身既可以存放堆内存中,又可以放在代码栈的内存中(与基本数据类型相同)。 GC 线程会从代码栈中的引用变量开始跟踪,从而判定哪些内存是正在使用的。如果 GC 线程通过这种方式,无法跟踪到某一块堆内存,那么 GC 就认为这块内存将不再使用了(因为代码中已经无法访问这块内存了)。

  通过这种有向图的内存管理方式,当一个内存对象失去了所有的引用之后,GC 就可以将其回收。反过来说,如果这个对象还存在引用,那么它将不会被 GC 回收,哪怕是 Java 虚拟机抛出 OutOfMemoryError 。

  Java内存泄露

  一般来说内存泄漏有两种情况。一种情况如在C/C++ 语言中的,在堆中的分配的内存,在没有将其释放掉的时候,就将所有能访问这块内存的方式都删掉(如指针重新赋值);另一种情况则是在内存对象明明已经不需要的时候,还仍然保留着这块内存和它的访问方式(引用)。第一种情况,在 Java 中已经由于垃圾回收机制的引入,得到了很好的解决。所以, Java 中的内存泄漏,主要指的是第二种情况。

  可能光说概念太抽象了,大家可以看一下这样的例子:

  1. Vector v = new  Vector( 10 );  
  2. for  ( int  i = 1 ;i < 100 ; i ++ ){  
  3. Object o = new  Object();  
  4. v.add(o);  
  5. o = null ;  
  6. }

  在这个例子中,代码栈中存在Vector 对象的引用 v 和 Object 对象的引用 o 。在 For 循环中,我们不断的生成新的对象,然后将其添加到 Vector 对象中,之后将 o 引用置空。问题是当 o 引用被置空后,如果发生 GC ,我们创建的 Object 对象是否能够被 GC 回收呢?答案是否定的。因为, GC 在跟踪代码栈中的引用时,会发现 v 引用,而继续往下跟踪,就会发现 v 引用指向的内存空间中又存在指向 Object 对象的引用。也就是说尽管 o 引用已经被置空,但是 Object 对象仍然存在其他的引用,是可以被访问到的,所以 GC 无法将其释放掉。如果在此循环之后, Object 对象对程序已经没有任何作用,那么我们就认为此 Java 程序发生了内存泄漏。

  尽管对于C/C++ 中的内存泄露情况来说, Java 内存泄露导致的破坏性小,除了少数情况会出现程序崩溃的情况外,大多数情况下程序仍然能正常运行。但是,在移动设备对于内存和 CPU 都有较严格的限制的情况下, Java 的内存溢出会导致程序效率低下、占用大量不需要的内存等问题。这将导致整个机器性能变差,严重的也会引起抛出 OutOfMemoryError ,导致程序崩溃。

  一般情况下内存泄漏的避免

  在不涉及复杂数据结构的一般情况下,Java 的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度。我们有时也将其称为“对象游离”。

  例如:

  1. public class FileSearch{  
  2.       private byte [] content;  
  3.       privateFile mFile;  
  4.      public FileSearch(File file){  
  5.       mFile = file;  
  6.       }  
  7.      public boolean hasString(String str){  
  8.          int size = getFileSize(mFile);  
  9.         content =  new  byte [size];  
  10.          loadFile(mFile, content);  
  11.          String s =  new String(content);  
  12.          return s.contains(str);  
  13.      }  
  14. }

posted @ 2011-12-16 14:20 顺其自然EVO 阅读(189) | 评论 (0)编辑 收藏

SQL Server 阻塞的常见原因和解决办法

  1、由于语句运行时间太长而导致的阻塞,语句本身在正常运行中,只须等待某些系统资源

  解决办法:

  a)语句本身有没有可优化的空间

  b)Sql Server 整体性能如何,是不是有资源瓶颈影响了语句执行速度,如 内存、硬盘 和 CPU 等

  2、由于一个未按预期提交的事务导致的阻塞

  这一类阻塞的特征,就是问题连接早就进入了空闲状态(sysprocesses.status='sleeping'和sysprocesses.cms='awaiting command'),但是,如果检查 sysprocesses.open_tran,就会发现它不为0,以及事务没有提交。这类问题很多都是因为应用端遇到了一个执行超时,或者其他原因,当时执行的语句倍提前终止了,但是连接还保留着。应用没有跟随发来的事务提交或回滚指令,导致一个事务被遗留在 Sql Server 里。

  解决办法:

  应用程序本身必须意识到任何语句都有可能遇到意外终止的情况,做好错误处理工作。这些工作包括:

  ● 在做 Sql Server 调用的时候,须加上错误捕捉和处理语句:If @@Trancount>0 RollBack Tran;(在程序中设置If @@Error<>0 Rollback Tran; 并不总是能执行到该语句)

  ● 设置连接属性"Set XACT_ABORT ON"。如果没有办法很规范应用程序的错误扑捉和处理语句,一个最快的方法就是在每个连接建立以后,或是容易出问题的存储过程开头,运行 "Set XACT_ABORT ON"

  ● 考虑是否要关闭连接池。发一句 sp_reset_connection 命令清理当前连接上次遗留下来的所有对象,包括回滚未提交的事务。

  3、由于客户端没有及时把结果集取出而导致的语句长时间运行

  语句在 Sql Server 内执行总时间不仅包含 Sql Server 的执行时间,还包含把结果集发给客户端的时间。如果结果集比较大,Sql Server 会分几次打包发出,没发一次,都要等待客户端的确认。只有确认以后,Sql Server 才会发送下一个结果集包。所有结果都发完以后,Sql Server才认为语句执行完毕,释放执行申请的资源(包括锁资源)。如果出于某种原因,客户端应用处理结果非常缓慢甚至没有响应,或者干脆不理睬 Sql Server 发送结果集的请求,则 Sql Server 会耐心的等待,银次会导致语句长时间执行而产生阻塞。

  解决办法:

  a)慎重返回大结果集

  b)如果a短期内不能实现,则尝试大结果集的连接使用 Read Uncommitted 事务隔离级别,这样查询就不会申请 S 锁了

posted @ 2011-12-15 15:48 顺其自然EVO 阅读(214) | 评论 (0)编辑 收藏

Java常量池详解之抓狂的面试题

http://bbs.51testing.com/viewthread.php?tid=516291&extra=&page=3


 今天My partner问我一个让他头疼的Java question,求输出结果:

  1. /** 
  2.  *  
  3.  * @author DreamSea 2011-11-19 
  4.  */ 
  5. public class IntegerTest { 
  6.     public static void main(String[] args) {     
  7.         objPoolTest(); 
  8.     } 
  9.     public static void objPoolTest() { 
  10.         Integer i1 = 40
  11.         Integer i2 = 40
  12.         Integer i3 = 0
  13.         Integer i4 = new Integer(40); 
  14.         Integer i5 = new Integer(40); 
  15.         Integer i6 = new Integer(0); 
  16.          
  17.         System.out.println("i1=i2\t" + (i1 == i2)); 
  18.         System.out.println("i1=i2+i3\t" + (i1 == i2 + i3)); 
  19.         System.out.println("i4=i5\t" + (i4 == i5)); 
  20.         System.out.println("i4=i5+i6\t" + (i4 == i5 + i6));     
  21.          
  22.         System.out.println();         
  23.     } 
  24. }

  输出结果:

i1=i2true
i1=i2+i3   true
i4=i5false
i4=i5+i6true

  看起来比较Easy的问题,但是Console输出的Result和我们所想的确恰恰相反,我们就疑惑了,这是为什么咧?

  最后通过网上搜索得知Java为了提高性能提供了和String类一样的对象池机制,当然Java的八种基本类型的包装类(Packaging Type)也有对象池机制。

  Integer i1=40;Java在编译的时候会执行将代码封装成Integer i1=Integer.valueOf(40);通过查看Source Code发现:

  Integer.valueOf()中有个内部类IntegerCache(类似于一个常量数组,也叫对象池),它维护了一个Integer数组cache,长度为(128+127+1)=256,Integer类中还有一个Static Block(静态块)。

  从这个静态块可以看出,Integer已经默认创建了数值【-128-127】的Integer缓存数据。所以使用Integer i1=40时,JVM会直接在该在对象池找到该值的引用。也就是说这种方式声明一个Integer对象时,JVM首先会在Integer对象的缓存池中查找有木有值为40的对象,如果有直接返回该对象的引用;如果没有,则使用New keyword创建一个对象,并返回该对象的引用地址。因为Java中【==】比较的是两个对象是否是同一个引用(即比较内存地址),i2和i2都是引用的同一个对象,So i1==i2结果为”true“;而使用new方式创建的i4=new Integer(40)、i5=new Integer(40),虽然他们的值相等,但是每次都会重新Create新的Integer对象,不会被放入到对象池中,所以他们不是同一个引用,输出false。

  对于i1==i2+i3、i4==i5+i6结果为True,是因为,Java的数学计算是在内存栈里操作的,Java会对i5、i6进行拆箱操作,其实比较的是基本类型(40=40+0),他们的值相同,因此结果为True。

  好了,我想说道这里大家应该都会对Integer对象池有了更进一步的了解了吧,我在诺诺的问一句如果把40改为400猜猜会输出什么?

i1=i2false
i1=i2+i3true
i4=i5false
i4=i5+i6true

  这是因为Integer i1=400,Integer i2=400他们的值已经超出了常量池的范围,JVM会对i1和i2各自创建新的对象(即Integer i1=new Integer(400)),所以他们不是同一个引用。

posted @ 2011-12-15 15:47 顺其自然EVO 阅读(250) | 评论 (0)编辑 收藏

Coverity谈“开发中测试”与程序员最常犯的编码错误

 Coverity公司位于美国加州旧金山,他们的产品包括Coverity Integrity Control、Coverity Static Analysis等一系列代码分析工具与解决方案。日前,Coverity公司产品副总Ezi Boteach先生就“开发中测试”、代码复查和开发人员最常犯的编码错误接受了采访。

  问题:能否介绍下Coverity的“开发中测试”理念和你们的Development Testing Platform?

  Ezi:“开发中测试”是新出现的一种技术,包括一系列流程和软件,例如静态分析。开发中测试的目的是要帮助开发人员、管理层和业务人员能在开发周期的早期,找到并修复质量和安全方面的问题,这些代码还在开发之中,不会影响上市时间、成本或客户满意度。

  “开发中测试”扩大了传统测试范围,可以包括功能测试性能测试和安全审核,为开发团队提供更快、更便捷的方式来测试代码中的缺陷,而且是以非侵入的方式。这种方式下,开发人员能够把注意力集中在创新上,管理层能够在开发周期早期尽早了解问题以作出决策,业务人员能持续向市场交付高质量的产品,获得竞争优势。

  问题:代码复查是人们高度推荐的编程实践。如果使用你们的产品,对于代码复查,您有什么建议?

  Ezi:代码复查是软件“开发中测试”很重要的部分,而且其成本很高,因为需要另一个开发人员来复审代码,很多时候这个开发人员还必须是资深人员。在代码复查之前先做静态分析,这能让代码复审过程更快,而且成本更低。使用自动化分析来检查变更以及于系统其他部分的集成点,以此来识别和消灭代码错误,代码复审就可以更集中于逻辑和功能错误,而不是代码的缺陷,这样做更划算,能够自动化,而且易于重复。

  我们推荐测试驱动开发所有的工具和实践,包括代码复审、单元测试和代码覆盖率。当然,要是能和Coverity的自动化代码测试工具一起使用就更好了。

  问题:你们的产品如何与像xUnit这样的工具一起配合使用?

  Ezi:单元测试是“开发中测试”的重要组成,需要支持测试驱动开发。使用Coverity 5.5,我们引入了“开发中测试”的平台,能够让多种不同工具与测试工作流集成。目前我们还不能专门与xUnit集成在一起,但是我们的客户现在能够很方便地把他们使用的测试工具与Coverity Development Testing平台集成。举个例子:Coverity 5.5.1版本包括与常用Java静态分析工具FindBugs的集成。这样的集成让管理人员能够降低维护多个测试工具的成本,并通过统一的工具来推行策略。开发人员也有统一的界面来查看缺陷,并排定解决的优先级。

  问题:你们的产品是否能与持续交付流程集成?

  Ezi:Coverity Static Analysis可以与多个构建系统集成,包括Jenkins这个常用的持续集成系统。一般来说,与Jenkins和持续集成系统的集成是为了确保所有的持续构建都能运行自动化代码测试工具。如果分析中发现了新的缺陷,一个构建版本就是失败的。这确保新的缺陷不会引入到交付的软件的主干代码中,而交付过程是持续交付流程的一部分。这也能保证失败的构建版本不会进入流程的下一个阶段,一般来说是QA阶段。Coverity就像是交付过程中的一道闸门。

  问题:除了使用你们的产品,您是否还能为开发人员和架构师提供一些其他的原则与实践?

  Ezi:确保软件的质量,防止安全漏洞,这需要良好协作、工具和开发流程管理这几方面的结合。从清晰的需求文档开始,这是开发任何新功能的基础。需求文档之后,就是功能和系统架构师完成的功能和需求设计。代码开发完成后,“开发中测试”应该是这个流程的有机部分。不仅仅是一个产品,而应该是流程和技术的组合,帮助开发组织在开发周期早期、撰写代码的时候,就能修复软件的问题,确保代价高昂的缺陷不会进入后续阶段和生产环境。

  架构师要确保软件的架构良好。这需要人工复审和架构分析,此外还要有经过考验的软件开发方法论。与之类似,开发人员也要保证,除了使用静态和动态分析的自动化测试之外,也要使用代码复审和单元测试。质量保证(QA)是任何软件开发过程中都很重要的阶段,以确保功能测试和性能测试顺利通过。最后,安全审核也很重要,保证在识别、修复、移除代码缺陷时不会带入新的安全漏洞。

  问题:根据Coverity收集的数据,您能否列举一些开发人员最常犯的错误?

  Ezi:开源项目SCAN(scan.coverity.com)能够很好地发现开发人员常犯的错误。从2006年开始,Coverity与美国国土安全部一起,研发了Coverity SCAN项目,来保证开源软件的安全性和完整性。Coverity SCAN分析了超过290个开源项目,包括Linux、Apache、PHP和Android,识别出49,654个缺陷,开源软件开发人员已经修复了超过15,000个缺陷。虾米的表格就展示出了开源软件中最常出现的缺陷,商业软件也与之类似。

 SCAN项目中的出现频率 风险程度 
NULL指针引用 27.60% 中 
资源泄露 23.19% 高 
非原意图表达式 9.76% 中 
读未初始化的值 8.41% 高 
释放后使用 5.91% 高 
缓冲区溢出 5.52% 高 

  很重要的一点要指出:像NULL指针引用、内存泄露和缓冲区溢出常常会带来很严重的质量和安全风险。很多这样的缺陷,使用传统的测试方法,有时难以找到。使用Coverity的工具会更易于发现类似问题。

  要想了解更多关于SCAN项目的信息,可以访问 2010 SCAN报告,其中包括对于Android核心代码的分析结果。

  问题:对于代码分析可视化的重要性,程序员们认识得越来越明白了。您能否列出3个最重要的相关分析图?

  Ezi:Coverity的Development Testing平台能以代码可视化形式让开发人员和管理层看到代码的质量。可视化能够在几个方面起到帮助作用:它有助于标识代码的所有者和缺陷,能帮助展示出软件代码的整体可读性,以及质量和安全风险较高的代码区域,还能有助于推行代码完整性的检查策略。

  只谈3个图很困难,但我想选的是:未解决的缺陷与已解决的缺陷的对比、每个软件组件中的缺陷个数、新的Integrity Control热度图。

posted @ 2011-12-14 15:58 顺其自然EVO 阅读(289) | 评论 (0)编辑 收藏

高手真经 13条Java核心技术

、>>>最高位用0填充,>>最高位用符号位填充 ,没有<<。

  2、强制转换是直接截断,要四舍五入的话需要用Math.round();

  3、boolean不要于任何数值类型进行转换。除非b?1:0

  4、Java没有内置字符串类型。

  5、String类没有提供用于修改字符串的方法,方便字符串共享。

  6、C++重载了==,可以用它来检测字符串的相等性。Java没有重载。C也不用==对字符串进行比较,而使用strcmp函数。Java的compareTo()方法与strcmp类似。

greeting.compareTo("Hello")==0

  7、length()返回代码单元数量;

  codePointCount()返回代码点数量。

  charAt(n)将返回位置n的代码单元,n介于0-s.length()-1。

  得到第i个代码点,

  1. greeting.offsetByCodePoints(0,i); 
  2. greeting.codePointAt(i);

  1. StringBuilder builder = new 
  2. StringBuilder();builder.append(ch/str); 
  3. or String completeString = builder.toString();

  返回一个与构建器或缓冲器相同的字符串。

  8、输入: Scanner类位于 java.util.*

  Console类可以实现控制台读取密码:

  1. Console cons = System.console(); 
  2. String username = cons.readLine("User name:"); 
  3. char[] passwd = cons.readPassword("Password:");

  9、被格式化的参数索引:

System.out.printf("%1$s %2$tB %2$te %2$ty""Due date:" , new Date());

  10、文件的输入与输出:

  1. Scanner in = new Scanner(new File("myfile.txt")); //如果文件名包含反斜杠 ,要转义,加一个反斜杠。 
  2. PrintWriter out = new PrintWriter("myfile.txt");

  如果用一个不存在的文件构造一个Scanner,或者用一个不能被创建的文件名构造一个PrintWriter,那么就会发异常。

  11、如果整数,浮点不能满足精度要求,可以使用java.math包中的两个类:BigInteger 和 BigDecimal

BigInteger a = BigInteger.valueOf(100);

  不能使用+ *来处理大数值,而是add 和multiply方法。

  12、

for(variable : collection) statement;

  打印数组更见的方法: Arrays.toString(a); //返回一个包含数组元素的字符串。

  数组的初始化:

  1. 1int[] smallPrimes = {2,3,4,5,6,7}; //不需要使用new。 
  2. 2new int[] {2,3,4,5,6,7//匿名初始化,将创建一个新的数组 并利用括号中提供的值进行初始化,数组的大小就是初始值的个数。

  Java允许数组长度为0。

  允许数组拷贝,这是两个变量引用同一个数组。如果要拷贝到一个新的数组 需要使用Arrays.copyOf(number , length),通常用这个方法来增加数组的大小,剩余的数值赋0,布尔型赋false。

  Java数组与C++数组在堆栈上有很大不同,但基本上与分配在heap上的数组指针一样。

int[] a = new int[100]; //java []被预定义为检查数组边界,而没有指针运算,即不能通过a+1得到数组下一个元素。

  不同于

int a[100//c++

  而等同于

int *a = new int[100]; //c++

  数组排序: sort

  快速打印一个二维数组的数据元素列表:Arrays.deepToString(a);

  Java实际上只有一维数组。

  13、命令行参数

java Message -g cruel world
args[0]: "-g" args[1]:"cruel" args[2]: world

posted @ 2011-12-14 15:57 顺其自然EVO 阅读(209) | 评论 (0)编辑 收藏

JVM分代垃圾回收策略的基础概念

 由于不同对象的生命周期不一样,因此在JVM的垃圾回收策略中有分代这一策略。本文介绍了分代策略的目标,如何分代,以及垃圾回收的触发因素。

  文章总结了JVM垃圾回收策略为什么要分代,如何分代,以及垃圾回收的触发因素。

  为什么要分代

  分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。

  在Java程序运行的过程中,会产生大量的对象,其中有些对象是与业务信息相关,比如Http请求中的Session对象、线程、Socket连接,这类对象跟业务直接挂钩,因此生命周期比较长。但是还有一些对象,主要是程序运行过程中生成的临时变量,这些对象生命周期会比较短,比如:String对象,由于其不变类的特性,系统会产生大量的这些对象,有些对象甚至只用一次即可回收。

  试想,在不进行对象存活时间区分的情况下,每次垃圾回收都是对整个堆空间进行回收,花费时间相对会长,同时,因为每次回收都需要遍历所有存活对象,但实际上,对于生命周期长的对象而言,这种遍历是没有效果的,因为可能进行了很多次遍历,但是他们依旧存在。因此,分代垃圾回收采用分治的思想,进行代的划分,把不同生命周期的对象放在不同代上,不同代上采用最适合它的垃圾回收方式进行回收。

  如何分代

  如图所示:

  如何分代

  虚拟机中的共划分为三个代:年轻代(Young Generation)、年老点(Old Generation)和持久代(Permanent Generation)。其中持久代主要存放的是Java类的类信息,与垃圾收集要收集的Java对象关系不大。年轻代和年老代的划分是对垃圾收集影响比较大的。

  年轻代:

  所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代分三个区。一个Eden区,两个Survivor区(一般而言)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来 对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。

 年老代:

  在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

  持久代:

  用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=<N>进行设置。

  什么情况下触发垃圾回收

  由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC有两种类型:Scavenge GC和Full GC。

  Scavenge GC

  一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。

  对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个对进行回收,所以比Scavenge GC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节。有如下原因可能导致Full GC:

  ◆ 年老代(Tenured)被写满

  ◆ 持久代(Perm)被写满

  ◆ System.gc()被显示调用

  ◆ 上一次GC之后Heap的各域分配策略动态变化


posted @ 2011-12-14 15:24 顺其自然EVO 阅读(189) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 347 348 349 350 351 352 353 354 355 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜