java线上分析
每日一句诗词
loading...
loading...
死锁
死锁模拟
1 | public class demo01 { |
分析
- 输入jps定位java进程
- jstack 查看进程栈信息
1 | "Thread-0" #16 prio=5 os_prio=0 cpu=0.00ms elapsed=89.15s tid=0x000001cffe8bf6e0 nid=13480 waiting for mo |
demo01的thread-0和thread-1都处于阻塞状态
jstack最后也很明确的输出:
发现一个死锁 thread-0 在等待一个 thread-1 所持有的object的资源
而 thread-1 在等待一个thread-0 所持有的object的资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 Found one Java-level deadlock:
=============================
"Thread-0":
waiting to lock monitor 0x000001cfd97eccc0 (object 0x00000007130789c0, a java.lang.Object),
which is held by "Thread-1"
"Thread-1":
waiting to lock monitor 0x000001cfd97ec780 (object 0x00000007130789b0, a java.lang.Object),
which is held by "Thread-0"
at day15.demo01$$Lambda$14/0x0000000800c031f0.run(Unknown Source)
at java.lang.Thread.run(java.base@18.0.1.1/Thread.java:833)
"Thread-1":
at day15.demo01.lambda$main$1(demo01.java:38)
- waiting to lock <0x00000007130789b0> (a java.lang.Object)
- locked <0x00000007130789c0> (a java.lang.Object)
at day15.demo01$$Lambda$15/0x0000000800c033f8.run(Unknown Source)
at java.lang.Thread.run(java.base@18.0.1.1/Thread.java:833)
Found 1 deadlock.
定位到是demo01.java的38行后就可以去破坏死锁条件解决死锁。
OOM
OOM模拟
1 | public class demo01 { |
在启动前先添加JVN参数:
1 -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\heap.hprof
- Xms: 设置JVM初始堆内存的大小。
- Xmx: 设置JVM最大堆内存的大小。
- XX:+HeapDumpOnOutOfMemoryError: 发生OOM异常时生成heap dump文件
- -XX:HeapDumpPath: dump文件保存位置
开始运行:
1 | java.lang.OutOfMemoryError: Java heap space |
分析
将生成的 heap.hprof
文件放入 jprofiler
中进行分析
我们查看最大类对象可以发现是list中含有了太多的byte[]数组
MySQL死锁
模拟
打开两个cmd窗口模拟两个session执行
session1:
1
2
3
4 begin;
update user set id = 4 where id = 1;
-- 先执行到这去执行session2的操作
update user set id = 5 where id = 2;session2:
1
2
3
4 begin;
update user set id = 6 where id = 2;
update user set id = 7 where id = 1;
-- 再去执行session1的后面的操作当最后输入session1的操作后
1
2 mysql> update user set id = 5 where id = 2;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction应该是MySQL的死锁检测检测出死锁了
当发生死锁是,我们可以用命令查看死锁日志
1 | show engine innodb staus |
查看死锁日志
2024-08-12 14:58:47 0x2b6c
* (1) TRANSACTION:
TRANSACTION 224533, ACTIVE 7 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1128, 2 row lock(s), undo log entries 2
MySQL thread id 11, OS thread handle 7480, query id 33 localhost ::1 root updating
update user set id = 7 where id = 1* (1) HOLDS THE LOCK(S):
RECORD LOCKS space id 516 page no 4 n bits 80 index PRIMARY of tabletest
.user
trx id 224533 lock_mode X locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 32
0: len 4; hex 80000002; asc ;;
1: len 6; hex 000000036d15; asc m ;;
2: len 7; hex 02000000d8166a; asc j;;
3: len 7; hex 7a65726f74776f; asc zerotwo;;
4: len 15; hex 7a65726f74776f403136332e636f6d; asc zerotwo@163.com;;
5: len 6; hex 313233343536; asc 123456;;* (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 516 page no 4 n bits 80 index PRIMARY of tabletest
.user
trx id 224533 lock_mode X locks rec but not gap waiting
Record lock, heap no 6 PHYSICAL RECORD: n_fields 6; compact format; info bits 32
0: len 4; hex 80000001; asc ;;
1: len 6; hex 000000036d10; asc m ;;
2: len 7; hex 01000000f5088b; asc ;;
3: len 7; hex 67696e636f6465; asc gincode;;
4: len 11; hex 47696e403136332e636f6d; asc Gin@163.com;;
5: len 6; hex 313233343536; asc 123456;;* (2) TRANSACTION:
TRANSACTION 224528, ACTIVE 23 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1128, 2 row lock(s), undo log entries 2
MySQL thread id 10, OS thread handle 14088, query id 34 localhost ::1 root updating
update user set id = 5 where id = 2* (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 516 page no 4 n bits 80 index PRIMARY of tabletest
.user
trx id 224528 lock_mode X locks rec but not gap
Record lock, heap no 6 PHYSICAL RECORD: n_fields 6; compact format; info bits 32
0: len 4; hex 80000001; asc ;;
1: len 6; hex 000000036d10; asc m ;;
2: len 7; hex 01000000f5088b; asc ;;
3: len 7; hex 67696e636f6465; asc gincode;;
4: len 11; hex 47696e403136332e636f6d; asc Gin@163.com;;
5: len 6; hex 313233343536; asc 123456;;* (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 516 page no 4 n bits 80 index PRIMARY of tabletest
.user
trx id 224528 lock_mode X locks rec but not gap waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 6; compact format; info bits 32
0: len 4; hex 80000002; asc ;;
1: len 6; hex 000000036d15; asc m ;;
2: len 7; hex 02000000d8166a; asc j;;
3: len 7; hex 7a65726f74776f; asc zerotwo;;
4: len 15; hex 7a65726f74776f403136332e636f6d; asc zerotwo@163.com;;
5: len 6; hex 313233343536; asc 123456;;* WE ROLL BACK TRANSACTION (2)
TRANSACTIONS
Trx id counter 224539
Purge done for trx’s n:o < 224539 undo n:o < 0 state: running but idle
History list length 0
LIST OF TRANSACTIONS FOR EACH SESSION:
—-TRANSACTION 284102103522432, not started
0 lock struct(s), heap size 1128, 0 row lock(s)
—-TRANSACTION 284102103521656, not started
0 lock struct(s), heap size 1128, 0 row lock(s)
—-TRANSACTION 284102103520880, not started
0 lock struct(s), heap size 1128, 0 row lock(s)
—-TRANSACTION 224533, ACTIVE 192 sec
3 lock struct(s), heap size 1128, 2 row lock(s), undo log entries 4
MySQL thread id 11, OS thread handle 7480, query id 33 localhost ::1 root
分析
- 死锁的SQL语句
1 | update user set id = 7 where id = 1 |
- 锁
事务1和事务2都是lock_mode X locks rec but not gap waiting
都是排他锁中的记录锁
X锁:排他锁、又称写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。
S锁:共享锁,又称读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
record Lock: 记录锁,只对当前记录进行上锁
Gap Lock:间隙锁,锁定一个范围,但不包括记录本身。GAP锁的目的,是为了防止同一事务的两次当前读,出现幻读的情况。
Next-Key Lock:rec+gap,锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要目的是解决幻读的问题。
MySQl加锁原理
在MySQL中,行级锁并不是直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,如果一条sql语句操作了主键索引,MySQL就会锁定这条主键索引;如果一条语句操作了非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引