一行代码引发的性能暴跌 10 倍

代码测试

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
import com.google.common.base.Stopwatch;
import java.util.concurrent.TimeUnit;
public class StackTest {
public static void main(String[] args) {
Stopwatch started = new Stopwatch();
started.start();
User user = null;
for (long i = 0; i < 1000_000_000; i++) {
user = new User();
}
started.stop();
System.out.println(started.elapsed(TimeUnit.MILLISECONDS) + "ms");
//不加打印 300ms
//加了打印 3000ms
// System.out.println(user);
}
}

class User {
private int age;
private String userName;

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}
}
阅读更多

ReentrantLock 源码解析

测试代码

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

public class App {
public static void main(String[] args) {

test1();
}

public static void test1() {
Lock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
lock.lock();
System.out.println("线程 " + Thread.currentThread().getId() + " 获得锁");
try {
Thread.sleep(50000000);
} catch (InterruptedException e) {
System.out.println("线程 " + Thread.currentThread().getId() + " 释放锁");
} finally {
lock.unlock();
}
});
t1.start();

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}


Thread t2 = new Thread(()->{
lock.lock();
System.out.println("线程 " + Thread.currentThread().getId() + " 获得锁");
lock.unlock();
});
t2.start();
Scanner scanner=new Scanner(System.in);
scanner.nextLine();
}

public static void test2(){

}
}
阅读更多

Java 对象深入探究

这篇博客是为了深入探究 Java 中对象的知识。

对象的创建

首先我们先看下一个简单创建对象的代码,看一个对象到底是如何在内存中创建的。

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
Person obj = new Person();
}


public class Person {
private int age=8;
private String name="fu";

}
阅读更多

synchronized 锁的升级过程

测试代码

为了更清楚的看 synchronized 的锁的升级的过程,我们用代码来打印对象的布局,使用的类库是:

1
2
3
4
5
6
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.14</version>
<scope>provided</scope>
</dependency>
阅读更多

synchronized 关键字

Synchronized 是 Java 中的一种锁的方式,是在 JVM 层面一种锁。在 jdk 1.6以前是一种重量级锁,在经历过优化后 Synchronized 锁已经没有那么“重”了。

Synchronized 有 3 种使用方式:

  1. 普通同步方法,锁是当前实例对象
  2. 静态同步方法,锁是当前类的Class对象
  3. 同步代码块,锁是Synchonized括号里配置的对象
阅读更多

一个正则表达式导致 CPU 高的问题排查过程

这篇文章记录一个正则表达是导致 CPU 高的问题排查。由于无法直接使用线上的代码测试,所以我自己把代码整理了下来,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public class AppMain {
public static void main(String[] args) throws InterruptedException {
final String regex="^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
final String email="blog.laofu.online.fuweilao@vip.qq.com#";
for (int i = 0; i < 1000000; i++) {
Matcher matcher = RegexUtils.matcher(regex, email);
matcher.find();
Thread.sleep(10);
// matcher.group();
}
}
}

当运行程序的时候,我们可以看到 java 的进程占用了 CPU 了 82.1%,由于我使用的服务器是 1核+2G, 所以 load avg 占用也很高。

image-20201005230510905

使用 top -H -p 4214 查看各个线程占用的情况

image-20201005230556871
hex
使用 printf '%x\n' 4217 把进程转成 16 进制值为 1079。执行 jstack 4214|grep 1079 -A 100得到线程的堆栈信息:

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
79
80
81
82
83
84
85
86
87
88
89
90
"main" #1 prio=5 os_prio=0 tid=0x00007f943004c800 nid=0x1079 runnable [0x00007f9439fe0000]
java.lang.Thread.State: RUNNABLE
at java.util.regex.Pattern$Curly.match0(Pattern.java:4264)
at java.util.regex.Pattern$Curly.match(Pattern.java:4248)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4672)
at java.util.regex.Pattern$Loop.match(Pattern.java:4799)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4731)
at java.util.regex.Pattern$Ques.match(Pattern.java:4196)
at java.util.regex.Pattern$Curly.match0(Pattern.java:4286)
at java.util.regex.Pattern$Curly.match(Pattern.java:4248)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4672)
at java.util.regex.Pattern$Loop.match(Pattern.java:4799)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4731)
// at java.util.regex.Pattern$Ques.match(Pattern.java:4196)
at java.util.regex.Pattern$Curly.match0(Pattern.java:4286)
at java.util.regex.Pattern$Curly.match(Pattern.java:4248)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4672)
at java.util.regex.Pattern$Loop.match(Pattern.java:4799)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4731)
at java.util.regex.Pattern$Ques.match(Pattern.java:4196)
at java.util.regex.Pattern$Curly.match0(Pattern.java:4286)
at java.util.regex.Pattern$Curly.match(Pattern.java:4248)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4672)
at java.util.regex.Pattern$Loop.match(Pattern.java:4799)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4731)
at java.util.regex.Pattern$Ques.match(Pattern.java:4195)
at java.util.regex.Pattern$Curly.match0(Pattern.java:4293)
at java.util.regex.Pattern$Curly.match(Pattern.java:4248)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4672)
at java.util.regex.Pattern$Loop.match(Pattern.java:4799)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4731)
at java.util.regex.Pattern$Ques.match(Pattern.java:4196)
at java.util.regex.Pattern$Curly.match0(Pattern.java:4286)
at java.util.regex.Pattern$Curly.match(Pattern.java:4248)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4672)
at java.util.regex.Pattern$Loop.match(Pattern.java:4799)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4731)
at java.util.regex.Pattern$Ques.match(Pattern.java:4196)
at java.util.regex.Pattern$Curly.match0(Pattern.java:4286)
at java.util.regex.Pattern$Curly.match(Pattern.java:4248)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4672)
at java.util.regex.Pattern$Loop.match(Pattern.java:4799)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4731)
at java.util.regex.Pattern$Ques.match(Pattern.java:4195)
at java.util.regex.Pattern$Curly.match0(Pattern.java:4293)
at java.util.regex.Pattern$Curly.match(Pattern.java:4248)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4672)
at java.util.regex.Pattern$Loop.match(Pattern.java:4799)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4731)
at java.util.regex.Pattern$Ques.match(Pattern.java:4196)
at java.util.regex.Pattern$Curly.match0(Pattern.java:4286)
at java.util.regex.Pattern$Curly.match(Pattern.java:4248)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4672)
at java.util.regex.Pattern$Loop.match(Pattern.java:4799)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4731)
at java.util.regex.Pattern$Ques.match(Pattern.java:4196)
at java.util.regex.Pattern$Curly.match0(Pattern.java:4286)
at java.util.regex.Pattern$Curly.match(Pattern.java:4248)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4672)
at java.util.regex.Pattern$Loop.match(Pattern.java:4799)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4731)
at java.util.regex.Pattern$Ques.match(Pattern.java:4195)
at java.util.regex.Pattern$Curly.match0(Pattern.java:4293)
at java.util.regex.Pattern$Curly.match(Pattern.java:4248)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4672)
at java.util.regex.Pattern$Loop.match(Pattern.java:4799)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4731)
at java.util.regex.Pattern$Ques.match(Pattern.java:4196)
at java.util.regex.Pattern$Curly.match0(Pattern.java:4286)
at java.util.regex.Pattern$Curly.match(Pattern.java:4248)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4672)
at java.util.regex.Pattern$Loop.match(Pattern.java:4799)
at java.util.regex.Pattern$GroupTail.match(Pattern.java:4731)
at java.util.regex.Pattern$Ques.match(Pattern.java:4196)
at java.util.regex.Pattern$Curly.match0(Pattern.java:4286)
at java.util.regex.Pattern$Curly.match(Pattern.java:4248)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4672)
at java.util.regex.Pattern$Loop.matchInit(Pattern.java:4815)
at java.util.regex.Pattern$Prolog.match(Pattern.java:4755)
at java.util.regex.Pattern$Begin.match(Pattern.java:3539)
at java.util.regex.Matcher.search(Matcher.java:1248)
at java.util.regex.Matcher.find(Matcher.java:637)
at org.rz.search.spider.AppMain.main(AppMain.java:13)

"VM Thread" os_prio=0 tid=0x00007f94300cc800 nid=0x1079 runnable

"VM Periodic Task Thread" os_prio=0 tid=0x00007f9430121000 nid=0x1079 waiting on condition

JNI global references: 5

从上面的堆栈信息可以看出来是正则的递归调用,导致了很深的堆栈。
查看最终的堆栈入口:at org.rz.search.spider.AppMain.main(AppMain.java:13) 可以断定问题是正则匹配的原因。

为什么一个正则会导致CPU飙高?

阅读更多