服务器CPU居高不下--解决问题历程

基本的概述

在一个服务器的集群上面,服务器的CPU长时间居高不下,响应的时间也一直很慢,即使扩容了服务器CPU的下降效果也不是很明显。

对于CPU过高的原因,可以总结到以下原因:

  • 太多的循环或者死循环

  • 加载了过多的数据,导致产生了很多的大对象

  • 产生了过多的对象,GC回收过于频繁(如:字符串拼接)

对于上面的情况,难点不是优化代码,难点在于定位到问题的所在,下面我们就用Dump抓包的方式来定位到问题的所在。介绍这个内容之前,我们要先回顾下.Net中垃圾回收的基础知识和一个工具的准备。


基础知识


垃圾回收触发条件

  • 代码显示调用System.GC的静态方法

  • windows报告低内存情况

  • CLR正在卸载AppDoamin

  • CLR正在关闭

阅读更多

Java反射和注解

反射

反射是指在运行的状态,对于任意一个类,都能够知道类里面的所有的属性和方法,并能够进行属性的赋值和方法的调用 。 在Java中使用Java.lang下面的Class来表示类型的”类” ,在JDK中定义接口如下

Java反射

其中T 表示运行时类的类型,如果不知道类型可以使用Class<?>,Class表示的实例表示正在运行的 Java 应用程序中的类(包含枚举) 和接口 , 所有的反射出来的结果都共享一个基类Class。

获得类型、方法、属性和构造器

在Java中有三种方法可以反射定制类的Class(以String类型为例):

1
2
3
4
5
6
1. 通过Class.from("Java.lang.String")    

2. 通过String.class

3. 通过类的实例对像中的getClass()方法 :"abc".getClass()

为了演示反射的功能,我们首先定义一个类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Person
{
private String userName;
private String userCode;
public String Sex;//字段

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

public String getUserCode() {
return userCode;
}

public void setUserCode(String userCode) {
this.userCode = userCode;
}

public String GetUserNameWithUserCode(){
return this.getUserName()+"_"+getUserCode();
}

public String GetUserNameWithUserCode(String prefix){
return prefix+"_"+ this.getUserName()+"_"+getUserCode();
}

public static String GetClassName(String prefix){
return prefix+"_Person";
}
}

获得Person类中的方法、属性和构造器,代码如下:

阅读更多

如何使用正则表达式

说到正则,可能很多人会很头疼这个东西,除了计算机好像很难快速的读懂这个东西,更不用说如果使用了。下面我们由浅入深来探索下正则表达式:

ps:此文适用于还有没有入门正则表达基础的读者

正则表达式可以简的定义成为一种字符串的匹配方式,至于来源可以参考:正则表达式{:target=_blank}

简单的使用

有这么一段字符串ABC12345ABC1234AB12C,对于这个字符串,如果想提取其中的字母,应该怎么办呢?

1
2
3
4
5
6
1. 可以找出所有的字母列表组成一个数组,[A,B,C...Z]     

2. 把字符串转成字符的数组,进行遍历

3. 如果是字母则继续,如果不是则直接继续下一个匹配

以上的分析过程则大概的讲述了不用正则表达式的过程,如果使用正则,怎么去写呢?

首先,我们是要匹配字母,那我要知道正则中用什么来表式字母呢?

1
2
3
4
5
6
7
8

[a-z] //匹配所有的小写字母
[A-Z] //匹配所有的大写字母
[a-zA-Z] //匹配所有的字母
[0-9] //匹配所有的数字
[0-9\.\-] //匹配所有的数字,句号和减号
[ \f\r\t\n] //匹配所有的白字符

阅读更多

SpringMVC 教程

SpringMVC 概述

   Spring 是目前比较流行的MVC框架,让POJO处理起来变的容易,也支持Rest的Url请求。采用松散的耦合可插拔的接口,比其它MVC接口更具有扩展性和灵活性

maven+spring+Idea 实现helloworld

下面就让我们用maven+Spring+Idea 实现一个 helloWorld的程序(至于环境的搭建可以直接到网上找个教程)

添加Maven项目

  1. 选择maven-archetype-webapp 这个项目类型

    maven创建

  2. 填写GroupId和ArtifactId后直接下一步直到创建完成

    Group

  3. Maven生成的目录如下:

    MVN_Index

添加SpringMVC引用

对于MVC的使用,我们首先需要添加对SpringMVC的引用,使用Maven可以方便的实现对jar包的引用和版本的管理。

  1. 添加SpringMVC的引用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
        <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.3.2.RELEASE</version>
    </dependency>
    ```



    2. 添加对jsp的页面解析 jstl的引用

    ``` xml
    <dependency>
    <groupId>Javax.servlet</groupId>
    <artifactId>Javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
    </dependency>
    <dependency>
    <groupId>Javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
    </dependency>
    ```

    #### 添加SpringMVC配置

    1. 添加Spring的配置文件,修改WEB-INF下面的web.config,添加如下内容

    ``` xml

    <!-- 配置DispatcherServlet -->
    <servlet>
    <servlet-name>spring-mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 配置DispatcherServlet ,配置SpringfMVC配置文件的位置和名称-->
    <!--这里可以不用通过contextConfigLocation来配置SpringMVC的配置文件,可以使用默认的配置文件的目录:/WEB-INF/<servlet-name>-servlet.xml-->
    <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    </servlet>
    <!--对应的Mapping-->
    <servlet-mapping>
    <servlet-name>spring-mvc</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>
  2. Spring文件配置MVC,在resources文件夹下面添加对应的spring-mvc.xml,添加如下内容:

     <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
         <property name="redirectContextRelative" value="true"></property>
         <property name="prefix" value="/WEB-INF/views/"></property>
         <property name="suffix" value=".jsp"></property>
     </bean>
     <!--配置扫描的包-->
     <context:component-scan base-package="Controller"></context:component-scan>
    
阅读更多

博客添加浮动目录

一直都想给自己的博客添加一个浮动的目录,在网上也找也几个,从易用性方面都不是太理想,所以今天才有了想法自己去写一个插件 。

需求


 1. 当打开博客的时候在右下角自动生成对应的目录  

 2. 支持拖拽移动  

 3. 可以点击展开和收缩  (目前未实现)

易用性方面,希望能够直接引用 js后,来执行一句代码来完成对应的动作 。

实现逻辑


  1. 读取页面的所有h1,h2,h3,h4,h5

  2. 根据对应的元素和排序,生成对应的数据,格式如下:

      [
        {
            text: "目录",
            level: 2,
            achorName: "目录",
            order: 1,
            chapterIndex: "1"
        }, {
            text: "UTF8的出现",
            level: 3,
            achorName: "utf8的出现",
            order: 6,
            chapterIndex: "1.5"
        }
    ]
    
  3. 根据数据生成对应的html

    CataLog

相关使用

代码地址:ICatalogJs

使用时候只需要引用js后,执行init方法:

阅读更多

字符编码探密--ASCII,UTF8,GBK,Unicode

目录

ASCII 的由来

在计算机的“原始社会”,有人想把日常的使用的语言使用计算机来表示, 我们知道在计算机的世界里面,只有0和1,为了解决尽量多的去表示字符,最终他们决定用8位0和1(一个字节)来表示字符,并且规定当机器读到这几个数据的时候,做出动作或者打印出指定的字符:

遇上0001 0000, 终端就换行;                

遇上0000 0111, 终端就向人们嘟嘟叫;        

遇上‭‭0001 1011‬, 打印机就打印反白的字,或者终端就用彩色显示字母。

这样就形成了最早期的ASCII码表{:target=”_blank”},并把小于32的字符称为“控制字符”,剩下的继续进行编写,一直到127个字符,这样一套完整的字符方案就完成了,终于可以把文字搬到计算机中了。

  当大家都在兴奋的可以在电脑的阅读的文章的时候,新的问题又出现了,随着计算机的普及,很多国家都使用了计算机,原来的ASCII码在使用英语的国家可以无障碍的使用,但到了其它国家就无法满足要求了,所以他们决定对后面没有用到的编码(128-255)表示自己国家的语言,并加上了其它的相关的符号,直到编码空间被全部用完,从128-255的字符集称为“ASCII的扩展字符集”。

汉字怎么办?

  等到中国人使用电脑的时候,发现已经没有编码供我们来存储对应的汉字了,连扩展的空间都已经被全部占满了。所以我们的前辈们用自己的智慧创造性提出了新的编码格式:


 1. 去除127之外的乱七八糟的字符串和符号    

 2. 如果一个字节且小于127号的字符,与原ASCII码意义相同    

 3. 如果有两个同时大于127的字符则表示一个汉字,所以就会有一个字符会占用两个字节的说法
阅读更多

说说.Net与Java中的字符串

Java字符串碰到的问题

在写Java程序碰到一个问题,而正是这个问题引发了我对字符串的思考,Java示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

public void TestStr(String success)
{

if(success=="Y"){
System.out.println("Equal");
}
else
{
System.out.println("Not Equal");
}

}

```

上面的这个函数很简单,但会随着调用的方式的不同而显示出不同的结果:

``` Java
public void CallMethod()
{
TestStr("Y");//Equal
TestStr("YY".substring(0,1));//Not Equal
}

```

对于这样的一个结果,我们可以先思考一个问题:" == " 这个运算符的作用?

1. 对于基础数据类型而言是比较值是否相同(作用与equal相同)

2. 对于引用类型,则比较地址是否一样


但如果理解上面的代码,我们还要理解Java中字符串的机制。由于字符串是比较常用的类型,为了保证性能,所以在设计字符串的时候会有一个“池”的概念。

- 字符一旦创建成功后,就不再发生变化,字符的运算也都是创建新的字符串对象

- 字符创建前,查找内存中是否已经存在相同的字符串,如果有则直接把地址给当前的对象,没有则直接创建新对象


所以对于上面的代码,因为在开始已经创建的“Y”字符串,所以后面出生现的所有的“Y”都是引用我们当前的“Y”,所以我们就可以理解为什么第一个是打印Equal,另一个是打印Not Equal.


### .Net中如何处理

而对于.Net来说,字符串的原理大致相同,如果是相同的代码,但运算的结果是与Java不一样的:

![dotnet](/img/assets/14/01.png)


我们知道在.Net string也是引用类型,但当“==”作用于两个引用类型的时候,比较则是地址,但在.Net中字符比较时,比较的却是值。这个归功于.Net对“==”的重载,[string源码](http://referencesource.microsoft.com/#mscorlib/system/string.cs,8281103e6f23cb5c){:target="_blank"}。如果想比较地址,则使用 object.ReferenceEquals()这个函数。


``` C#

public static bool operator == (String a, String b)
{
return String.Equals(a, b);
}

```

对于.Net运算符重载的这个动作,个人觉得更贴近日常的使用习惯,因为在编码的过程中,字符串中绝大多数的使用场景都是值,而不是引用。而对Java而言,保证的运算的原汁原味,少了人为的封装的干扰,使用是注意区分,习惯了反而觉得更为合理。

### 几个疑问


#### 字符串是引用类型,为什么不使用new来创建对象?

字符串是一个特殊的引用对象 ,声明就是创建了一个对象,如果使用new,则会重复的创建对象(Java中可以使用new创建,.Net中则直接不允许这样操作),浪费内存,如下:

``` Java    

String str=new String("1234");

String str1="1234";

两种的定义方式相同,但是使用new的时候,又额外分配了内存空间。

字符串是引用类型,但是传参的时候却无法修改它的值?有其它的引用类型有什么不同?

  public void CallMethod(){

    String str="abc";
    AddSuffix(str);

    System.out.println(str);//打印出abc
  }

  public void AddSuffix(String x){

      x=x+"123";
  }

当我们去调用这个函数的时候,发现str的值却没有发生改变。 因为在调用AddSuffix 函数时,str把自己作拷贝成一个副本传递给形参x,当对x赋值的时候,系统重新创建了一个字符对象,把引用的地址给x,此处是重新创建对象,而不是修改原来的字符串对象(字符串不可更改)。两种方式示意如下:

字符串

字符串

阅读更多

linux下sublime如何使用中文

原来在使用linux的时候最大的诟病是在sublime text下面不能写中文,各种百度和搜索都没能解决,但现在又重新下linux下面做开发,又要重新面对这个问题,好在问题已经有了很好的解决方案。

使用方法

  • 首先更新你的系统 :

    
    sudo apt-get update && sudo apt-get upgrade
    
  • 选择一个目录后,用git clone 下面地址:

    
    git clone https://github.com/lyfeyaj/sublime-text-imfix.git
    
  • 使用命令进入sublime- text- imfix 路径 :

    
    cd sublime-text-imfix
    
  • 运行以下脚本

  ./sublime-imfix
  • 完成后 重启电脑。

    解决Ubuntu下Sublime Text 3无法输入中文

阅读更多

jekyll如何使用中文路径

出现问题

最近在使用jekyll在本地预览自己写的博客无法正常打开,而提交到github上却可以正常解析。看了一下发现是文件写的博客有什么变化,原来是因为博客的markdown文件使用了中文文件名,jekyll无法正常解析出现乱码。

解决方法:

修改安装目录\Ruby22-x64\lib\ruby\2.2.0\webrick\httpservlet下的filehandler.rb文件,建议先备份。找到下列两处,添加一句(+的一行为添加部分)

1
2
3
4
5

path = req.path_info.dup.force_encoding(Encoding.find("filesystem"))
+ path.force_encoding("UTF-8") # 加入编码
if trailing_pathsep?(req.path_info)


    break if base == "/"
    + base.force_encoding("UTF-8") #加入編碼
    break unless File.directory?(File.expand_path(res.filename + base))

修改完重新jekyll serve即可支持中文文件名。

阅读更多

多线程如何排队执行

场景

有一个这样场景,程序会有一个非常耗时的操作,但要求耗时的操作完成后,再顺序的执行一个不耗时的操作,而且这个程序的调用,可能存在同时调用的情况。

具体的模型如下:

moxing

从Start开始触发了5个线程,经过一个longTimeJob同时执行,我们不关心longJob的执行时间和先后顺序,根据Start的先后顺序来执行一个ShortJob。下面我们用代码来模拟上面的过程。

举例说明:有ABCD 4个线程,进入的顺序也是ABCD,A耗时3s,B耗时7s,C耗时1s,D耗时3s. 所以如果当4个线程都同时开始执行时,完成的先后顺序为 CADB,但我们要求的顺序是ABCD,也就是说C要等待AB执行完后,才能继续后续的工作。

我们可以用请求bing搜索来模拟longTimeJob,根据传入的序列来决定请求多少次,主要模拟方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

private static async Task Test()
{
var arry = new[]
{
10, 9, 8, 7, 6, 5, 4, 3, 2, 1
};
var listTask = new List<Task<int>>();
foreach (var i in arry)
{
var i1 = i;
var task = Task.Run(() => DoJob(i1));

listTask.Add(task);
}

foreach (var task in listTask)
{
Console.WriteLine("输出-->:" + await task);//
}
}

public static Task<int> DoJob(int o)
{
return Task.Run(() =>
{
DoLongTimeThing(o);
return o;
});
}

public static void DoLongTimeThing(int i)
{
Console.WriteLine("执行-->:" + i);
for (int j = 0; j < i; j++)
{
HttpGet("http://cn.bing.com/");
}

Console.WriteLine("执行完毕-->:" + i);
}

public static string HttpGet(string url)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";

HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
string content = reader.ReadToEnd();
return content;
}
catch (Exception e)
{
return e.Message;
}

}



执行结果:

taskjob

阅读更多