-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
3016 lines (2692 loc) · 453 KB
/
search.xml
File metadata and controls
3016 lines (2692 loc) · 453 KB
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>CPU缓存与MESI协议</title>
<url>/posts/1a5fbe08.html</url>
<content><![CDATA[<h2 id="引言"><a class="markdownIt-Anchor" href="#引言"></a> 引言</h2>
<h2 id=""><a class="markdownIt-Anchor" href="#"></a> </h2>
<img src="/posts/1a5fbe08/cpu%E7%BB%93%E6%9E%84%E5%9B%BE.svg" class="" title="cpu结构图">
]]></content>
<categories>
<category>CS</category>
</categories>
<tags>
<tag>cpu</tag>
<tag>CS</tag>
</tags>
</entry>
<entry>
<title>记录一次排查因线程WAITING导致应用假死的经历</title>
<url>/posts/7e818be6.html</url>
<content><![CDATA[<h3 id="背景"><a class="markdownIt-Anchor" href="#背景"></a> 背景</h3>
<p>在一个阳光明媚的下午,我正在悠哉游哉的在工位上畅游网络世界(摸鱼 😃 ),忽然心里有点不好的预感,果然哈,企业微信里产品经理弹了一条消息给我说测试服务器的系统登录进去获取不到菜单,我随即连接到测试服务器,心想这种问题重新运行下应该就没事了,到系统管理后台目录重新跑下 <a href="http://start.sh">start.sh</a> 脚本,想不到,竟然也被这问题折腾了一个小时,因此记录一下排查过程</p>
<h3 id="过程"><a class="markdownIt-Anchor" href="#过程"></a> 过程</h3>
<ol>
<li>当重新运行了start.sh脚本后,系统正常运行成功,但是过一会就立马又是卡死状态,我打开浏览器登录进入系统,f12打开控制台看到获取菜单的请求一直在加载中,没有拿到响应,使用 tail 命令查看日志信息,请求日志和响应的日志信息也都能够正常输出</li>
<li>心想这是什么玩意,响应也返回了为什么会卡死呢,猜测是不是网关出了问题,随即又去排查网关的日志,发现只输出了请求的日志,没有输出响应的日志,难道是网关的问题吗,随即remote debug网关服务(测试服务器在本地机房,为了方便调试开启了remote debug),将断点打在了 <code>NettyRoutingFilter#filter</code> 方法中(NettyRoutingFilter是最终的发送请求的过滤器),然后让客户端的请求发送过来,发现只有请求发送过去,迟迟接受不到系统服务的响应(没有配置responseTimeout配置,会一直等待服务的响应),因此知道问题点肯定发生在系统服务侧了</li>
<li>排查是不是系统服务所在服务器的硬盘空间或者内存不足了导致的,
<ul>
<li>使用 <code>df -h</code> 命令查看还有100多G的空间,不是磁盘空间不足引发的</li>
<li>使用<code>free -m -h</code>获取空闲内存也还要10多G,</li>
<li>使用<code>jstat -gc 进程id 2000 5 </code> 查看java进程内存使用情况,也都是正常的</li>
</ul>
</li>
<li>看到都是正常的,顿时就毫无头绪了,只能疯狂摸头以示不解,突然脑海里闪现了一点思路,既然请求无响应,是不是线程被阻塞住了,随即 <code>jastck 进程id</code> 命令打印下服务的线程信息,查看下请求线程的状态堆栈,随即就发现了问题根源所在</li>
</ol>
<pre class="line-numbers language-java" data-language="java"><code class="language-java">只给出请求线程的状态以及堆栈信息
<span class="token string">"http-nio-6002-exec-2"</span> #<span class="token number">151</span> daemon prio<span class="token operator">=</span><span class="token number">5</span> os_prio<span class="token operator">=</span><span class="token number">0</span> tid<span class="token operator">=</span><span class="token number">0x000070fb4d7c8000</span> nid<span class="token operator">=</span><span class="token number">0x3c3178</span> waiting <span class="token keyword">for</span> monitor entry <span class="token punctuation">[</span><span class="token number">0x000070fce07fb000</span><span class="token punctuation">]</span>
<span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span></span>Thread<span class="token punctuation">.</span>State</span><span class="token operator">:</span> <span class="token constant">BLOCKED</span> <span class="token punctuation">(</span>on object monitor<span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>rabbitmq<span class="token punctuation">.</span>client<span class="token punctuation">.</span>impl<span class="token punctuation">.</span></span>SocketFrameHandler</span><span class="token punctuation">.</span><span class="token function">writeFrame</span><span class="token punctuation">(</span><span class="token class-name">SocketFrameHandler</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">170</span><span class="token punctuation">)</span>
<span class="token operator">-</span> waiting <span class="token keyword">to</span> <span class="token namespace">lock</span> <span class="token generics"><span class="token punctuation"><</span>0x00000000eac318c0<span class="token punctuation">></span></span> <span class="token punctuation">(</span>a <span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span>DataOutputStream</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>rabbitmq<span class="token punctuation">.</span>client<span class="token punctuation">.</span>impl<span class="token punctuation">.</span></span>AMQConnection</span><span class="token punctuation">.</span><span class="token function">writeFrame</span><span class="token punctuation">(</span><span class="token class-name">AMQConnection</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">562</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>rabbitmq<span class="token punctuation">.</span>client<span class="token punctuation">.</span>impl<span class="token punctuation">.</span></span>AMQCommand</span><span class="token punctuation">.</span><span class="token function">transmit</span><span class="token punctuation">(</span><span class="token class-name">AMQCommand</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">130</span><span class="token punctuation">)</span>
<span class="token operator">-</span> locked <span class="token generics"><span class="token punctuation"><</span>0x00000000fa3a3cb0<span class="token punctuation">></span></span> <span class="token punctuation">(</span>a <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>rabbitmq<span class="token punctuation">.</span>client<span class="token punctuation">.</span>impl<span class="token punctuation">.</span></span>CommandAssembler</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>rabbitmq<span class="token punctuation">.</span>client<span class="token punctuation">.</span>impl<span class="token punctuation">.</span></span>AMQChannel</span><span class="token punctuation">.</span><span class="token function">quiescingTransmit</span><span class="token punctuation">(</span><span class="token class-name">AMQChannel</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">447</span><span class="token punctuation">)</span>
<span class="token operator">-</span> locked <span class="token generics"><span class="token punctuation"><</span>0x00000000fa3a38d8<span class="token punctuation">></span></span> <span class="token punctuation">(</span>a <span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span></span>Object</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>rabbitmq<span class="token punctuation">.</span>client<span class="token punctuation">.</span>impl<span class="token punctuation">.</span></span>AMQChannel</span><span class="token punctuation">.</span><span class="token function">quiescingTransmit</span><span class="token punctuation">(</span><span class="token class-name">AMQChannel</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">429</span><span class="token punctuation">)</span>
<span class="token operator">-</span> locked <span class="token generics"><span class="token punctuation"><</span>0x00000000fa3a38d8<span class="token punctuation">></span></span> <span class="token punctuation">(</span>a <span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span></span>Object</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>rabbitmq<span class="token punctuation">.</span>client<span class="token punctuation">.</span>impl<span class="token punctuation">.</span></span>AMQChannel</span><span class="token punctuation">.</span><span class="token function">quiescingRpc</span><span class="token punctuation">(</span><span class="token class-name">AMQChannel</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">346</span><span class="token punctuation">)</span>
<span class="token operator">-</span> locked <span class="token generics"><span class="token punctuation"><</span>0x00000000fa3a38d8<span class="token punctuation">></span></span> <span class="token punctuation">(</span>a <span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span></span>Object</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>rabbitmq<span class="token punctuation">.</span>client<span class="token punctuation">.</span>impl<span class="token punctuation">.</span></span>AMQChannel</span><span class="token punctuation">.</span><span class="token function">rpc</span><span class="token punctuation">(</span><span class="token class-name">AMQChannel</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">337</span><span class="token punctuation">)</span>
<span class="token operator">-</span> locked <span class="token generics"><span class="token punctuation"><</span>0x00000000fa3a38d8<span class="token punctuation">></span></span> <span class="token punctuation">(</span>a <span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span></span>Object</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>rabbitmq<span class="token punctuation">.</span>client<span class="token punctuation">.</span>impl<span class="token punctuation">.</span></span>AMQChannel</span><span class="token punctuation">.</span><span class="token function">privateRpc</span><span class="token punctuation">(</span><span class="token class-name">AMQChannel</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">277</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>rabbitmq<span class="token punctuation">.</span>client<span class="token punctuation">.</span>impl<span class="token punctuation">.</span></span>AMQChannel</span><span class="token punctuation">.</span><span class="token function">exnWrappingRpc</span><span class="token punctuation">(</span><span class="token class-name">AMQChannel</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">138</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>rabbitmq<span class="token punctuation">.</span>client<span class="token punctuation">.</span>impl<span class="token punctuation">.</span></span>ChannelN</span><span class="token punctuation">.</span><span class="token keyword">open</span><span class="token punctuation">(</span><span class="token class-name">ChannelN</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">133</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>rabbitmq<span class="token punctuation">.</span>client<span class="token punctuation">.</span>impl<span class="token punctuation">.</span></span>ChannelManager</span><span class="token punctuation">.</span><span class="token function">createChannel</span><span class="token punctuation">(</span><span class="token class-name">ChannelManager</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">176</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>rabbitmq<span class="token punctuation">.</span>client<span class="token punctuation">.</span>impl<span class="token punctuation">.</span></span>AMQConnection</span><span class="token punctuation">.</span><span class="token function">createChannel</span><span class="token punctuation">(</span><span class="token class-name">AMQConnection</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">553</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>amqp<span class="token punctuation">.</span>rabbit<span class="token punctuation">.</span>connection<span class="token punctuation">.</span></span>SimpleConnection</span><span class="token punctuation">.</span><span class="token function">createChannel</span><span class="token punctuation">(</span><span class="token class-name">SimpleConnection</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">57</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>amqp<span class="token punctuation">.</span>rabbit<span class="token punctuation">.</span>connection<span class="token punctuation">.</span></span>CachingConnectionFactory</span>$<span class="token class-name">ChannelCachingConnectionProxy</span><span class="token punctuation">.</span><span class="token function">createBareChannel</span><span class="token punctuation">(</span><span class="token class-name">CachingConnectionFactory</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">1365</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>amqp<span class="token punctuation">.</span>rabbit<span class="token punctuation">.</span>connection<span class="token punctuation">.</span></span>CachingConnectionFactory</span>$<span class="token class-name">ChannelCachingConnectionProxy</span><span class="token punctuation">.</span>access$<span class="token function">200</span><span class="token punctuation">(</span><span class="token class-name">CachingConnectionFactory</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">1351</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>amqp<span class="token punctuation">.</span>rabbit<span class="token punctuation">.</span>connection<span class="token punctuation">.</span></span>CachingConnectionFactory</span><span class="token punctuation">.</span><span class="token function">doCreateBareChannel</span><span class="token punctuation">(</span><span class="token class-name">CachingConnectionFactory</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">672</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>amqp<span class="token punctuation">.</span>rabbit<span class="token punctuation">.</span>connection<span class="token punctuation">.</span></span>CachingConnectionFactory</span><span class="token punctuation">.</span><span class="token function">createBareChannel</span><span class="token punctuation">(</span><span class="token class-name">CachingConnectionFactory</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">655</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>amqp<span class="token punctuation">.</span>rabbit<span class="token punctuation">.</span>connection<span class="token punctuation">.</span></span>CachingConnectionFactory</span><span class="token punctuation">.</span><span class="token function">getCachedChannelProxy</span><span class="token punctuation">(</span><span class="token class-name">CachingConnectionFactory</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">625</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>amqp<span class="token punctuation">.</span>rabbit<span class="token punctuation">.</span>connection<span class="token punctuation">.</span></span>CachingConnectionFactory</span><span class="token punctuation">.</span><span class="token function">getChannel</span><span class="token punctuation">(</span><span class="token class-name">CachingConnectionFactory</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">516</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>amqp<span class="token punctuation">.</span>rabbit<span class="token punctuation">.</span>connection<span class="token punctuation">.</span></span>CachingConnectionFactory</span><span class="token punctuation">.</span>access$<span class="token function">1700</span><span class="token punctuation">(</span><span class="token class-name">CachingConnectionFactory</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">102</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>amqp<span class="token punctuation">.</span>rabbit<span class="token punctuation">.</span>connection<span class="token punctuation">.</span></span>CachingConnectionFactory</span>$<span class="token class-name">ChannelCachingConnectionProxy</span><span class="token punctuation">.</span><span class="token function">createChannel</span><span class="token punctuation">(</span><span class="token class-name">CachingConnectionFactory</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">1370</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>amqp<span class="token punctuation">.</span>rabbit<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>RabbitTemplate</span><span class="token punctuation">.</span><span class="token function">doExecute</span><span class="token punctuation">(</span><span class="token class-name">RabbitTemplate</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">2079</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>amqp<span class="token punctuation">.</span>rabbit<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>RabbitTemplate</span><span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token class-name">RabbitTemplate</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">2047</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>amqp<span class="token punctuation">.</span>rabbit<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>RabbitTemplate</span><span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token class-name">RabbitTemplate</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">994</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>amqp<span class="token punctuation">.</span>rabbit<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>RabbitTemplate</span><span class="token punctuation">.</span><span class="token function">convertAndSend</span><span class="token punctuation">(</span><span class="token class-name">RabbitTemplate</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">1100</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>amqp<span class="token punctuation">.</span>rabbit<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>RabbitTemplate</span><span class="token punctuation">.</span><span class="token function">convertAndSend</span><span class="token punctuation">(</span><span class="token class-name">RabbitTemplate</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">1091</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>xx<span class="token punctuation">.</span>logger<span class="token punctuation">.</span>reports<span class="token punctuation">.</span></span>RabbitLoggerReport</span><span class="token punctuation">.</span><span class="token function">reportLog</span><span class="token punctuation">(</span><span class="token class-name">RabbitLoggerReport</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">25</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>xx<span class="token punctuation">.</span>logger<span class="token punctuation">.</span>reports<span class="token punctuation">.</span></span>DefaultLoggerReportChain</span><span class="token punctuation">.</span><span class="token function">reportLog</span><span class="token punctuation">(</span><span class="token class-name">DefaultLoggerReportChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">71</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>xx<span class="token punctuation">.</span>logger<span class="token punctuation">.</span>reports<span class="token punctuation">.</span></span>DefaultLoggerReportChain</span><span class="token punctuation">.</span><span class="token function">reportLog</span><span class="token punctuation">(</span><span class="token class-name">DefaultLoggerReportChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">72</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>xx<span class="token punctuation">.</span>logger<span class="token punctuation">.</span>reports<span class="token punctuation">.</span></span>DefaultLoggerReportChain</span><span class="token punctuation">.</span><span class="token function">reportLog</span><span class="token punctuation">(</span><span class="token class-name">DefaultLoggerReportChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">60</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>xx<span class="token punctuation">.</span>logger<span class="token punctuation">.</span>advisor<span class="token punctuation">.</span></span>LogReportInterceptor</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">LogReportInterceptor</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">53</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>aop<span class="token punctuation">.</span>framework<span class="token punctuation">.</span></span>ReflectiveMethodInvocation</span><span class="token punctuation">.</span><span class="token function">proceed</span><span class="token punctuation">(</span><span class="token class-name">ReflectiveMethodInvocation</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">186</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>xx<span class="token punctuation">.</span>logger<span class="token punctuation">.</span>advisor<span class="token punctuation">.</span></span>LogReportInterceptor</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">LogReportInterceptor</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">46</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>aop<span class="token punctuation">.</span>framework<span class="token punctuation">.</span></span>ReflectiveMethodInvocation</span><span class="token punctuation">.</span><span class="token function">proceed</span><span class="token punctuation">(</span><span class="token class-name">ReflectiveMethodInvocation</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">186</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>aop<span class="token punctuation">.</span>framework<span class="token punctuation">.</span></span>CglibAopProxy</span>$<span class="token class-name">DynamicAdvisedInterceptor</span><span class="token punctuation">.</span><span class="token function">intercept</span><span class="token punctuation">(</span><span class="token class-name">CglibAopProxy</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">688</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>xx<span class="token punctuation">.</span>sys<span class="token punctuation">.</span>modules<span class="token punctuation">.</span>system<span class="token punctuation">.</span>controller<span class="token punctuation">.</span></span>SysFileController</span>$$<span class="token class-name">EnhancerBySpringCGLIB</span>$$bc9efccd<span class="token punctuation">.</span><span class="token function">queryByRelevanceId</span><span class="token punctuation">(</span><span class="token generics"><span class="token punctuation"><</span>generated<span class="token punctuation">></span></span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">sun<span class="token punctuation">.</span>reflect<span class="token punctuation">.</span></span>GeneratedMethodAccessor357</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">Unknown</span> <span class="token class-name">Source</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">sun<span class="token punctuation">.</span>reflect<span class="token punctuation">.</span></span>DelegatingMethodAccessorImpl</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">DelegatingMethodAccessorImpl</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">43</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>reflect<span class="token punctuation">.</span></span>Method</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">Method</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">498</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>method<span class="token punctuation">.</span>support<span class="token punctuation">.</span></span>InvocableHandlerMethod</span><span class="token punctuation">.</span><span class="token function">doInvoke</span><span class="token punctuation">(</span><span class="token class-name">InvocableHandlerMethod</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">190</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>method<span class="token punctuation">.</span>support<span class="token punctuation">.</span></span>InvocableHandlerMethod</span><span class="token punctuation">.</span><span class="token function">invokeForRequest</span><span class="token punctuation">(</span><span class="token class-name">InvocableHandlerMethod</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">138</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span>mvc<span class="token punctuation">.</span>method<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span>ServletInvocableHandlerMethod</span><span class="token punctuation">.</span><span class="token function">invokeAndHandle</span><span class="token punctuation">(</span><span class="token class-name">ServletInvocableHandlerMethod</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">104</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span>mvc<span class="token punctuation">.</span>method<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span>RequestMappingHandlerAdapter</span><span class="token punctuation">.</span><span class="token function">invokeHandlerMethod</span><span class="token punctuation">(</span><span class="token class-name">RequestMappingHandlerAdapter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">892</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span>mvc<span class="token punctuation">.</span>method<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span>RequestMappingHandlerAdapter</span><span class="token punctuation">.</span><span class="token function">handleInternal</span><span class="token punctuation">(</span><span class="token class-name">RequestMappingHandlerAdapter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">797</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span>mvc<span class="token punctuation">.</span>method<span class="token punctuation">.</span></span>AbstractHandlerMethodAdapter</span><span class="token punctuation">.</span><span class="token function">handle</span><span class="token punctuation">(</span><span class="token class-name">AbstractHandlerMethodAdapter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">87</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span></span>DispatcherServlet</span><span class="token punctuation">.</span><span class="token function">doDispatch</span><span class="token punctuation">(</span><span class="token class-name">DispatcherServlet</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">1039</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span></span>DispatcherServlet</span><span class="token punctuation">.</span><span class="token function">doService</span><span class="token punctuation">(</span><span class="token class-name">DispatcherServlet</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">942</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span></span>FrameworkServlet</span><span class="token punctuation">.</span><span class="token function">processRequest</span><span class="token punctuation">(</span><span class="token class-name">FrameworkServlet</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">1005</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span></span>FrameworkServlet</span><span class="token punctuation">.</span><span class="token function">doGet</span><span class="token punctuation">(</span><span class="token class-name">FrameworkServlet</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">897</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span>http<span class="token punctuation">.</span></span>HttpServlet</span><span class="token punctuation">.</span><span class="token function">service</span><span class="token punctuation">(</span><span class="token class-name">HttpServlet</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">634</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span></span>FrameworkServlet</span><span class="token punctuation">.</span><span class="token function">service</span><span class="token punctuation">(</span><span class="token class-name">FrameworkServlet</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">882</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span>http<span class="token punctuation">.</span></span>HttpServlet</span><span class="token punctuation">.</span><span class="token function">service</span><span class="token punctuation">(</span><span class="token class-name">HttpServlet</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">741</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">internalDoFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">231</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">166</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>tomcat<span class="token punctuation">.</span>websocket<span class="token punctuation">.</span>server<span class="token punctuation">.</span></span>WsFilter</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">WsFilter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">53</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">internalDoFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">193</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">166</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>alibaba<span class="token punctuation">.</span>druid<span class="token punctuation">.</span>support<span class="token punctuation">.</span>http<span class="token punctuation">.</span></span>WebStatFilter</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">WebStatFilter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">124</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">internalDoFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">193</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">166</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>xx<span class="token punctuation">.</span>common<span class="token punctuation">.</span>xss<span class="token punctuation">.</span></span>XssFilter</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">XssFilter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">55</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">internalDoFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">193</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">166</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter<span class="token punctuation">.</span></span>RequestContextFilter</span><span class="token punctuation">.</span><span class="token function">doFilterInternal</span><span class="token punctuation">(</span><span class="token class-name">RequestContextFilter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">99</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter<span class="token punctuation">.</span></span>OncePerRequestFilter</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">OncePerRequestFilter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">107</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">internalDoFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">193</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">166</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter<span class="token punctuation">.</span></span>FormContentFilter</span><span class="token punctuation">.</span><span class="token function">doFilterInternal</span><span class="token punctuation">(</span><span class="token class-name">FormContentFilter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">92</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter<span class="token punctuation">.</span></span>OncePerRequestFilter</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">OncePerRequestFilter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">107</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">internalDoFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">193</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">166</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter<span class="token punctuation">.</span></span>HiddenHttpMethodFilter</span><span class="token punctuation">.</span><span class="token function">doFilterInternal</span><span class="token punctuation">(</span><span class="token class-name">HiddenHttpMethodFilter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">93</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter<span class="token punctuation">.</span></span>OncePerRequestFilter</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">OncePerRequestFilter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">107</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">internalDoFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">193</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">166</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter<span class="token punctuation">.</span></span>CharacterEncodingFilter</span><span class="token punctuation">.</span><span class="token function">doFilterInternal</span><span class="token punctuation">(</span><span class="token class-name">CharacterEncodingFilter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">200</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter<span class="token punctuation">.</span></span>OncePerRequestFilter</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">OncePerRequestFilter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">107</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">internalDoFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">193</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>ApplicationFilterChain</span><span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ApplicationFilterChain</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">166</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>StandardWrapperValve</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">StandardWrapperValve</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">200</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>StandardContextValve</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">StandardContextValve</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">96</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>authenticator<span class="token punctuation">.</span></span>AuthenticatorBase</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">AuthenticatorBase</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">490</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>StandardHostValve</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">StandardHostValve</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">139</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>valves<span class="token punctuation">.</span></span>ErrorReportValve</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">ErrorReportValve</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">92</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span>StandardEngineValve</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span><span class="token class-name">StandardEngineValve</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">74</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>catalina<span class="token punctuation">.</span>connector<span class="token punctuation">.</span></span>CoyoteAdapter</span><span class="token punctuation">.</span><span class="token function">service</span><span class="token punctuation">(</span><span class="token class-name">CoyoteAdapter</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">343</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>coyote<span class="token punctuation">.</span>http11<span class="token punctuation">.</span></span>Http11Processor</span><span class="token punctuation">.</span><span class="token function">service</span><span class="token punctuation">(</span><span class="token class-name">Http11Processor</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">408</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>coyote<span class="token punctuation">.</span></span>AbstractProcessorLight</span><span class="token punctuation">.</span><span class="token function">process</span><span class="token punctuation">(</span><span class="token class-name">AbstractProcessorLight</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">66</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>coyote<span class="token punctuation">.</span></span>AbstractProtocol</span>$<span class="token class-name">ConnectionHandler</span><span class="token punctuation">.</span><span class="token function">process</span><span class="token punctuation">(</span><span class="token class-name">AbstractProtocol</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">836</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>tomcat<span class="token punctuation">.</span>util<span class="token punctuation">.</span>net<span class="token punctuation">.</span></span>NioEndpoint</span>$<span class="token class-name">SocketProcessor</span><span class="token punctuation">.</span><span class="token function">doRun</span><span class="token punctuation">(</span><span class="token class-name">NioEndpoint</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">1747</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>tomcat<span class="token punctuation">.</span>util<span class="token punctuation">.</span>net<span class="token punctuation">.</span></span>SocketProcessorBase</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token class-name">SocketProcessorBase</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">49</span><span class="token punctuation">)</span>
<span class="token operator">-</span> locked <span class="token generics"><span class="token punctuation"><</span>0x00000000f97c1de0<span class="token punctuation">></span></span> <span class="token punctuation">(</span>a <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>tomcat<span class="token punctuation">.</span>util<span class="token punctuation">.</span>net<span class="token punctuation">.</span></span>NioEndpoint</span>$<span class="token class-name">NioSocketWrapper</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span></span>ThreadPoolExecutor</span><span class="token punctuation">.</span><span class="token function">runWorker</span><span class="token punctuation">(</span><span class="token class-name">ThreadPoolExecutor</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">1149</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span></span>ThreadPoolExecutor</span>$<span class="token class-name">Worker</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token class-name">ThreadPoolExecutor</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">624</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>tomcat<span class="token punctuation">.</span>util<span class="token punctuation">.</span>threads<span class="token punctuation">.</span></span>TaskThread</span>$<span class="token class-name">WrappingRunnable</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token class-name">TaskThread</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">61</span><span class="token punctuation">)</span>
at <span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span></span>Thread</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token class-name">Thread</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">748</span><span class="token punctuation">)</span>
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<ol start="5">
<li>可以看到我们的请求线程已经被BLOCKED了,线程堆栈表明是rabbitmq消息发送阻塞住了,因为我们的日志切面会将请求的日志信息发送到rabbitmq中,所以堆栈里出现了rabbitmq,这也解释了控制台可以正常输出,但是请求就是没有返回相应</li>
<li>随即连接rabbitmq的服务器,打印日志看下错误信息,发现磁盘不足导致消息根本无法写入,使用<code>df -h</code> 指令查看硬盘空间情况,发现只有几百k的空间了,因为这台服务器只运行了docker容器,猜测是docker的运行日志未清理导致空间占用的过大,然后编写了清理日志的脚本</li>
</ol>
<pre class="line-numbers language-bash" data-language="bash"><div class="caption"><span>title</span></div><code class="language-bash"><span class="token shebang important">#!/bin/sh </span>
<span class="token builtin class-name">echo</span> <span class="token string">"======== start clean docker containers logs ========"</span>
<span class="token assign-left variable">logs</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">find</span> /var/lib/docker/containers/ <span class="token parameter variable">-name</span> *-json.log<span class="token variable">)</span></span>
<span class="token keyword">for</span> <span class="token for-or-select variable">log</span> <span class="token keyword">in</span> <span class="token variable">$logs</span>
<span class="token keyword">do</span>
<span class="token builtin class-name">echo</span> <span class="token string">"clean logs : <span class="token variable">$log</span>"</span>
<span class="token function">cat</span> /dev/null <span class="token operator">></span> <span class="token variable">$log</span>
<span class="token keyword">done</span>
<span class="token builtin class-name">echo</span> <span class="token string">"======== end clean docker containers logs ========"</span> <span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>再刷新浏览器请求果然立马成功了,长吁一口气,不过由于docker会一直运行,产生的日志大小会源源不断的增长,为了治本设置了docker的日志大小上限,以免再出现这种情况<br />
7. 修改<code>/etc/docker/daemon.json</code> 文件,将下面的内容复制进去再 <code>systemctl restart docker</code> 即可</p>
<pre class="line-numbers language-yaml" data-language="yaml"><code class="language-yaml"><span class="token comment"># 增加下面的内容</span>
"log<span class="token punctuation">-</span>driver"<span class="token punctuation">:</span><span class="token string">"json-file"</span><span class="token punctuation">,</span>
<span class="token key atrule">"log-opts"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>"max<span class="token punctuation">-</span>size"<span class="token punctuation">:</span><span class="token string">"1g"</span><span class="token punctuation">,</span> "max<span class="token punctuation">-</span>file"<span class="token punctuation">:</span><span class="token string">"3"</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span></span></code></pre>]]></content>
<categories>
<category>工作log</category>
</categories>
</entry>
<entry>
<title>Hotspot源码剖析Java方法执行流程</title>
<url>/posts/48bea92d.html</url>
<content><![CDATA[<h4 id="1-背景"><a class="markdownIt-Anchor" href="#1-背景"></a> 1. 背景</h4>
<p>在学习JMM的过程中产生了对想探索栈帧内存分配的底层原理的想法,故此写下这篇博客以梳理和学习hotspot虚拟机是如何执行java方法并且分配栈帧空间的</p>
<blockquote>
<p>本篇博客是基于Hotspot的 CppInterpreter.cpp[^1] 所编写的,其他基于硬件架构而开发的汇编代码让人晦涩难懂,不过原理都一样的,所以无需纠结</p>
</blockquote>
<h4 id="2-相关概念"><a class="markdownIt-Anchor" href="#2-相关概念"></a> 2. 相关概念</h4>
<h5 id="特殊寄存器"><a class="markdownIt-Anchor" href="#特殊寄存器"></a> 特殊寄存器</h5>
<ul>
<li><code>sp(stack pointer)</code>: 栈顶指针,每个线程都会有私有的栈,而这个指针指向线程栈的顶部,压栈出栈都依靠此指针的移动</li>
<li><code>fp(frame pointer)</code>:栈帧指针,jvm会给每个调用的方法分配一个栈帧,用于存储方法的局部变量,参数和返回地址等,而这个指针指向栈帧的起始地址</li>
<li><code>bcp(byte code poiniter)</code>:字节码指针,存储当前执行的Java字节码指令的位置,每执行完当前指令,就会更新为下一条要执行的字节码指令的位置</li>
<li><code>pc(program counter pointer)</code>:程序计数器,用于存储下一条即将要执行的指令的内存地址
<ul>
<li>注意与上面的bcp是不同的作用,pc是cpu所使用的,而bcp是jvm所使用的,一条字节码指令对应着底层多条指令</li>
</ul>
</li>
</ul>
<h5 id="调用方法字节码指令"><a class="markdownIt-Anchor" href="#调用方法字节码指令"></a> 调用方法字节码指令</h5>
<p>在java中调用方法的代码根据不同的情况会被编译成为不同的字节码指令,有如下4种</p>
<ul>
<li><code>invokevirtual</code>: 虚方法,通过对象引用调用实例方法,虚方法只有在运行时根据对象的实际类型才能确定具体调用哪个类的方法</li>
<li><code>invokeinterface</code>:接口方法,通过接口引用调用接口方法</li>
<li><code>invokespecial</code>:特殊方法调用,三种情况:实例构造方法,私有方法,通过super关键字调用父类方法</li>
<li><code>invokestatic</code>:调用类的静态方法</li>
</ul>
<h3 id="3-源码剖析"><a class="markdownIt-Anchor" href="#3-源码剖析"></a> 3. 源码剖析</h3>
<blockquote>
<p>基于jdk8u cppInterpreter.cpp解析代码,不过鉴于由Gary Benson贡献的代码截至目前最新版<code>25</code>并未发生大的改变(不过命名从cpp前缀修改为zero了,所以若是查看最新版请注意替换)</p>
</blockquote>
<h4 id="方法入口"><a class="markdownIt-Anchor" href="#方法入口"></a> 方法入口</h4>
<p>hotspot会对执行的java方法进行分类<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>,对于普通的方法通常对应着两种</p>
<ul>
<li><code>zerolocals</code>:表示方法需要进行局部变量初始化,以存储方法参数和方法内局部变量</li>
<li><code>zerolocals_synchronized</code>:和上面一样,只是方法上增加了synchronized修饰<br />
hotspot解释器会对这两种方法会生成一个<code>EntryPoint</code>(根据架构不同可能会生成不同的<code>EntryPoint</code>),后续执行此类的方法直接从该<code>EntryPoint</code>进入执行 (其实就是策略模式)</li>
</ul>
<p>创建<code>EntryPoint</code>的调用链<br />
如果是Threads::create_vm -> init_globals() -> stubRoutines_init1() -> StubRoutines::initialize2() -> StubGenerator_generate(&buffer, true) -> generate_all() -> generate_method_entry<br />
<code>stubGenerator_zero.cpp</code></p>
<pre class="line-numbers language-C++" data-language="C++"><code class="language-C++">// 如果是其他的解释器,此方法会对各种类型的方法创建 EntryPoint,但当前是c++编写的解释器,所以直接用c++代码去执行java代码,没有为其生成 EntryPoint
#undef method_entry
void generate_initial() {
// Generates all stubs and initializes the entry points
// entry points that exist in all platforms Note: This is code
// that could be shared among different platforms - however the
// benefit seems to be smaller than the disadvantage of having a
// much more complicated generator structure. See also comment in
// stubRoutines.hpp.
StubRoutines::_forward_exception_entry = ShouldNotCallThisStub();
/**
* call_stub 函数地址
*/
StubRoutines::_call_stub_entry = (address) call_stub;
StubRoutines::_catch_exception_entry = ShouldNotCallThisStub();
// atomic calls
StubRoutines::_atomic_xchg_entry = ShouldNotCallThisStub();
StubRoutines::_atomic_xchg_ptr_entry = ShouldNotCallThisStub();
StubRoutines::_atomic_cmpxchg_entry = ShouldNotCallThisStub();
StubRoutines::_atomic_cmpxchg_ptr_entry = ShouldNotCallThisStub();
StubRoutines::_atomic_cmpxchg_long_entry = ShouldNotCallThisStub();
StubRoutines::_atomic_add_entry = ShouldNotCallThisStub();
StubRoutines::_atomic_add_ptr_entry = ShouldNotCallThisStub();
StubRoutines::_fence_entry = ShouldNotCallThisStub();
// amd64 does this here, sparc does it in generate_all()
StubRoutines::_handler_for_unsafe_access_entry =
ShouldNotCallThisStub();
}
}<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>可以看下stubGenerator_template</p>
<p>在cppInter</p>
<pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">void CppInterpreterGenerator::generate_all() {
AbstractInterpreterGenerator::generate_all();
{ CodeletMark cm(_masm, "result handlers for native calls");
#define method_entry(kind) Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind)
{ CodeletMark cm(_masm, "(kind = frame_manager)");
// all non-native method kinds
method_entry(zerolocals);
method_entry(zerolocals_synchronized);
method_entry(empty);
method_entry(accessor);
method_entry(abstract);
method_entry(java_lang_math_sin );
method_entry(java_lang_math_cos );
method_entry(java_lang_math_tan );
method_entry(java_lang_math_abs );
method_entry(java_lang_math_sqrt );
method_entry(java_lang_math_log );
method_entry(java_lang_math_log10 );
method_entry(java_lang_math_pow );
method_entry(java_lang_math_exp );
method_entry(java_lang_ref_reference_get);
initialize_method_handle_entries();
Interpreter::_native_entry_begin = Interpreter::code()->code_end();
method_entry(native);
method_entry(native_synchronized);
Interpreter::_native_entry_end = Interpreter::code()->code_end();
}<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<pre class="line-numbers language-C++" data-language="C++"><code class="language-C++">
address AbstractInterpreterGenerator::generate_method_entry(
AbstractInterpreter::MethodKind kind) {
address entry_point = NULL;
switch (kind) {
case Interpreter::zerolocals:
case Interpreter::zerolocals_synchronized:
break;
// ... 省略了其他分支条件的判断
}
// 由于是zerolocals或者zerolocals_synchronied
if (entry_point == NULL)
entry_point = ((InterpreterGenerator*) this)->generate_normal_entry(false);
return entry_point;
}
address InterpreterGenerator::generate_normal_entry(bool synchronized) {
assert(synchronized == false, "should be");
return generate_entry((address) CppInterpreter::normal_entry);
}
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<h4 id="分析java方法执行流程"><a class="markdownIt-Anchor" href="#分析java方法执行流程"></a> 分析java方法执行流程</h4>
<ol>
<li>调用java方法入口<br />
<code>javaCalls.cpp#call_virtual</code></li>
</ol>
<pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">void JavaCalls::call_virtual(JavaValue* result, KlassHandle spec_klass, Symbol* name, Symbol* signature, JavaCallArguments* args, TRAPS) {
CallInfo callinfo;
Handle receiver = args->receiver();
KlassHandle recvrKlass(THREAD, receiver.is_null() ? (Klass*)NULL : receiver->klass());
LinkResolver::resolve_virtual_call(
callinfo, receiver, recvrKlass, spec_klass, name, signature,
KlassHandle(), false, true, CHECK);
methodHandle method = callinfo.selected_method();
assert(method.not_null(), "should have thrown exception");
// Invoke the method
JavaCalls::call(result, method, args, CHECK);
}<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">int CppInterpreter::normal_entry(Method* method, intptr_t UNUSED, TRAPS) {
JavaThread *thread = (JavaThread *) THREAD;
// Allocate and initialize our frame.
// 为方法分配并初始化栈帧,其内部就会创建我们的局部变量表,以及设置bcp指针
InterpreterFrame *frame = InterpreterFrame::build(method, CHECK_0);
// 保存我们的栈帧到线程栈中
thread->push_zero_frame(frame);
// Execute those bytecodes!
// 进入执行字节码的主入口
main_loop(0, THREAD);
// No deoptimized frames on the stack
return 0;
}
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<ol start="2">
<li>构建方法栈帧</li>
</ol>
<pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">InterpreterFrame *InterpreterFrame::build(Method* const method, TRAPS) {
JavaThread *thread = (JavaThread *) THREAD;
ZeroStack *stack = thread->zero_stack();
// Calculate the size of the frame we'll build, including
// any adjustments to the caller's frame that we'll make.
// 方法内部局部变量数量
int extra_locals = 0;
// 监视器占用空间大小
int monitor_words = 0;
// 局部变量表变量个数/长度
int stack_words = 0;
// 注意,上面的参数编译期就可以确定下来,可以通过javap -l .class 看到局部变量表信息
// 所以这里只是取出来然后分配一个大小合适的局部变量表来存储方法中所操作的变量
if (!method->is_native()) {
// 局部变量表长度 - 方法参数 得到 方法内部定义的局部变量个数
extra_locals = method->max_locals() - method->size_of_parameters();
// 局部变量表solt个数
stack_words = method->max_stack();
}
if (method->is_synchronized()) {
// 方法是同步的,那么需要分配一个solt存储
monitor_words = frame::interpreter_frame_monitor_size();
}
// 检查是否栈溢出
stack->overflow_check(
extra_locals + header_words + monitor_words + stack_words, CHECK_NULL);
// Adjust the caller's stack frame to accomodate any additional
// local variables we have contiguously with our parameters.
// 预先填充
for (int i = 0; i < extra_locals; i++)
stack->push(0);
// 分配局部变量表空间了
intptr_t *locals;
if (method->is_native())
// 入股是native方法
locals = stack->sp() + (method->size_of_parameters() - 1);
else
locals = stack->sp() + (method->max_locals() - 1);
stack->push(0); // next_frame, filled in later
intptr_t *fp = stack->sp();
assert(fp - stack->sp() == next_frame_off, "should be");
stack->push(INTERPRETER_FRAME);
assert(fp - stack->sp() == frame_type_off, "should be");
interpreterState istate =
(interpreterState) stack->alloc(sizeof(BytecodeInterpreter));
assert(fp - stack->sp() == istate_off, "should be");
istate->set_locals(locals);
istate->set_method(method);
istate->set_self_link(istate);
istate->set_prev_link(NULL);
istate->set_thread(thread);
istate->set_bcp(method->is_native() ? NULL : method->code_base());
istate->set_constants(method->constants()->cache());
istate->set_msg(BytecodeInterpreter::method_entry);
istate->set_oop_temp(NULL);
istate->set_mdx(NULL);
istate->set_callee(NULL);
istate->set_monitor_base((BasicObjectLock *) stack->sp());
if (method->is_synchronized()) {
BasicObjectLock *monitor =
(BasicObjectLock *) stack->alloc(monitor_words * wordSize);
oop object;
if (method->is_static())
object = method->constants()->pool_holder()->java_mirror();
else
object = (oop) (void*)locals[0];
monitor->set_obj(object);
}
istate->set_stack_base(stack->sp());
istate->set_stack(stack->sp() - 1);
if (stack_words)
stack->alloc(stack_words * wordSize);
istate->set_stack_limit(stack->sp() - 1);
return (InterpreterFrame *) fp;
}<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<ol start="4">
<li>主入口</li>
</ol>
<pre class="line-numbers language-c" data-language="c"><code class="language-c">
<span class="token keyword">void</span> CppInterpreter<span class="token operator">::</span><span class="token function">main_loop</span><span class="token punctuation">(</span><span class="token keyword">int</span> recurse<span class="token punctuation">,</span> TRAPS<span class="token punctuation">)</span> <span class="token punctuation">{</span>
# 当前java线程
JavaThread <span class="token operator">*</span>thread <span class="token operator">=</span> <span class="token punctuation">(</span>JavaThread <span class="token operator">*</span><span class="token punctuation">)</span> THREAD<span class="token punctuation">;</span>
<span class="token comment">// 线程栈</span>
ZeroStack <span class="token operator">*</span>stack <span class="token operator">=</span> thread<span class="token operator">-></span><span class="token function">zero_stack</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// If we are entering from a deopt we may need to call</span>
<span class="token comment">// ourself a few times in order to get to our frame.</span>
<span class="token comment">// 递归调用,不太理解</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>recurse<span class="token punctuation">)</span>
<span class="token function">main_loop</span><span class="token punctuation">(</span>recurse <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> THREAD<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 转换为解释器栈帧类型</span>
InterpreterFrame <span class="token operator">*</span>frame <span class="token operator">=</span> thread<span class="token operator">-></span><span class="token function">top_zero_frame</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">as_interpreter_frame</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 解释器状态[该状态信息包含了执行方法所需要的一切信息,包括不仅限于当前线程,栈,栈帧,本地变量表,pc,sp 地址]</span>
interpreterState istate <span class="token operator">=</span> frame<span class="token operator">-></span><span class="token function">interpreter_state</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
Method<span class="token operator">*</span> method <span class="token operator">=</span> istate<span class="token operator">-></span><span class="token function">method</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">intptr_t</span> <span class="token operator">*</span>result <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> result_slots <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token comment">// 循环里是因为有执行的指令条件不满足,从而进入对应的分支再执行指令</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>true<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// We can set up the frame anchor with everything we want at</span>
<span class="token comment">// this point as we are thread_in_Java and no safepoints can</span>
<span class="token comment">// occur until we go to vm mode. We do have to clear flags</span>
<span class="token comment">// on return from vm but that is it.</span>
<span class="token comment">// 设置java线程的sp以及fp寄存器,并且让java pc地址清空</span>
<span class="token comment">// src\cpu\zero\vm\javaFrameAnchor_zero.hpp#set(intptr_t* sp, address pc, ZeroFrame* fp)</span>
thread<span class="token operator">-></span><span class="token function">set_last_Java_frame</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Call the interpreter</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>JvmtiExport<span class="token operator">::</span><span class="token function">can_post_interpreter_events</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
BytecodeInterpreter<span class="token operator">::</span><span class="token function">runWithChecks</span><span class="token punctuation">(</span>istate<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">else</span>
<span class="token comment">// 这里就是执行字节码指令的关键之处,会</span>
BytecodeInterpreter<span class="token operator">::</span><span class="token function">run</span><span class="token punctuation">(</span>istate<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">fixup_after_potential_safepoint</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Clear the frame anchor</span>
thread<span class="token operator">-></span><span class="token function">reset_last_Java_frame</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Examine the message from the interpreter to decide what to do</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>istate<span class="token operator">-></span><span class="token function">msg</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> BytecodeInterpreter<span class="token operator">::</span>call_method<span class="token punctuation">)</span> <span class="token punctuation">{</span>
Method<span class="token operator">*</span> callee <span class="token operator">=</span> istate<span class="token operator">-></span><span class="token function">callee</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Trim back the stack to put the parameters at the top</span>
stack<span class="token operator">-></span><span class="token function">set_sp</span><span class="token punctuation">(</span>istate<span class="token operator">-></span><span class="token function">stack</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Make the call</span>
Interpreter<span class="token operator">::</span><span class="token function">invoke_method</span><span class="token punctuation">(</span>callee<span class="token punctuation">,</span> istate<span class="token operator">-></span><span class="token function">callee_entry_point</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> THREAD<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">fixup_after_potential_safepoint</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Convert the result</span>
istate<span class="token operator">-></span><span class="token function">set_stack</span><span class="token punctuation">(</span>stack<span class="token operator">-></span><span class="token function">sp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Restore the stack</span>
stack<span class="token operator">-></span><span class="token function">set_sp</span><span class="token punctuation">(</span>istate<span class="token operator">-></span><span class="token function">stack_limit</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Resume the interpreter</span>
istate<span class="token operator">-></span><span class="token function">set_msg</span><span class="token punctuation">(</span>BytecodeInterpreter<span class="token operator">::</span>method_resume<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>istate<span class="token operator">-></span><span class="token function">msg</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> BytecodeInterpreter<span class="token operator">::</span>more_monitors<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> monitor_words <span class="token operator">=</span> frame<span class="token operator">::</span><span class="token function">interpreter_frame_monitor_size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Allocate the space</span>
stack<span class="token operator">-></span><span class="token function">overflow_check</span><span class="token punctuation">(</span>monitor_words<span class="token punctuation">,</span> THREAD<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>HAS_PENDING_EXCEPTION<span class="token punctuation">)</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
stack<span class="token operator">-></span><span class="token function">alloc</span><span class="token punctuation">(</span>monitor_words <span class="token operator">*</span> wordSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Move the expression stack contents</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">intptr_t</span> <span class="token operator">*</span>p <span class="token operator">=</span> istate<span class="token operator">-></span><span class="token function">stack</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> p <span class="token operator"><</span> istate<span class="token operator">-></span><span class="token function">stack_base</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> p<span class="token operator">++</span><span class="token punctuation">)</span>
<span class="token operator">*</span><span class="token punctuation">(</span>p <span class="token operator">-</span> monitor_words<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token operator">*</span>p<span class="token punctuation">;</span>
<span class="token comment">// Move the expression stack pointers</span>
istate<span class="token operator">-></span><span class="token function">set_stack_limit</span><span class="token punctuation">(</span>istate<span class="token operator">-></span><span class="token function">stack_limit</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> monitor_words<span class="token punctuation">)</span><span class="token punctuation">;</span>
istate<span class="token operator">-></span><span class="token function">set_stack</span><span class="token punctuation">(</span>istate<span class="token operator">-></span><span class="token function">stack</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> monitor_words<span class="token punctuation">)</span><span class="token punctuation">;</span>
istate<span class="token operator">-></span><span class="token function">set_stack_base</span><span class="token punctuation">(</span>istate<span class="token operator">-></span><span class="token function">stack_base</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> monitor_words<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Zero the new monitor so the interpreter can find it.</span>
<span class="token punctuation">(</span><span class="token punctuation">(</span>BasicObjectLock <span class="token operator">*</span><span class="token punctuation">)</span> istate<span class="token operator">-></span><span class="token function">stack_base</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">set_obj</span><span class="token punctuation">(</span><span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Resume the interpreter</span>
istate<span class="token operator">-></span><span class="token function">set_msg</span><span class="token punctuation">(</span>BytecodeInterpreter<span class="token operator">::</span>got_monitors<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>istate<span class="token operator">-></span><span class="token function">msg</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> BytecodeInterpreter<span class="token operator">::</span>return_from_method<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Copy the result into the caller's frame</span>
result_slots <span class="token operator">=</span> type2size<span class="token punctuation">[</span>method<span class="token operator">-></span><span class="token function">result_type</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token function">assert</span><span class="token punctuation">(</span>result_slots <span class="token operator">>=</span> <span class="token number">0</span> <span class="token operator">&&</span> result_slots <span class="token operator"><=</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token string">"what?"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
result <span class="token operator">=</span> istate<span class="token operator">-></span><span class="token function">stack</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> result_slots<span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>istate<span class="token operator">-></span><span class="token function">msg</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> BytecodeInterpreter<span class="token operator">::</span>throwing_exception<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">assert</span><span class="token punctuation">(</span>HAS_PENDING_EXCEPTION<span class="token punctuation">,</span> <span class="token string">"should do"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>istate<span class="token operator">-></span><span class="token function">msg</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> BytecodeInterpreter<span class="token operator">::</span>do_osr<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Unwind the current frame</span>
thread<span class="token operator">-></span><span class="token function">pop_zero_frame</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Remove any extension of the previous frame</span>
<span class="token keyword">int</span> extra_locals <span class="token operator">=</span> method<span class="token operator">-></span><span class="token function">max_locals</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> method<span class="token operator">-></span><span class="token function">size_of_parameters</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
stack<span class="token operator">-></span><span class="token function">set_sp</span><span class="token punctuation">(</span>stack<span class="token operator">-></span><span class="token function">sp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> extra_locals<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Jump into the OSR method</span>
Interpreter<span class="token operator">::</span><span class="token function">invoke_osr</span><span class="token punctuation">(</span>
method<span class="token punctuation">,</span> istate<span class="token operator">-></span><span class="token function">osr_entry</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> istate<span class="token operator">-></span><span class="token function">osr_buf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> THREAD<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token function">ShouldNotReachHere</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// Unwind the current frame</span>
thread<span class="token operator">-></span><span class="token function">pop_zero_frame</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Pop our local variables</span>
stack<span class="token operator">-></span><span class="token function">set_sp</span><span class="token punctuation">(</span>stack<span class="token operator">-></span><span class="token function">sp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> method<span class="token operator">-></span><span class="token function">max_locals</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Push our result</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> result_slots<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// Adjust result to smaller</span>
<span class="token keyword">union</span> <span class="token punctuation">{</span>
<span class="token class-name">intptr_t</span> res<span class="token punctuation">;</span>
jint res_jint<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
res <span class="token operator">=</span> result<span class="token punctuation">[</span><span class="token operator">-</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>result_slots <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
BasicType t <span class="token operator">=</span> method<span class="token operator">-></span><span class="token function">result_type</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">is_subword_type</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
res_jint <span class="token operator">=</span> <span class="token punctuation">(</span>jint<span class="token punctuation">)</span><span class="token function">narrow</span><span class="token punctuation">(</span>t<span class="token punctuation">,</span> res_jint<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
stack<span class="token operator">-></span><span class="token function">push</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>具体分类类别可查看 <code>AbstractInterpreter.hpp$MethodKind</code>, 特别的是Math类,该类下的数学计算方法都会进行内联 <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
]]></content>
<categories>
<category>源码分析</category>
<category>hotspot</category>
</categories>
</entry>
<entry>
<title>JVM Atomic源码解析</title>
<url>/posts/6961ed95.html</url>
<content><![CDATA[<h1 id="引言"><a class="markdownIt-Anchor" href="#引言"></a> 引言</h1>
<p>在日常工作的过程中,常常会使用到一些<code>共享变量</code>来监控某些指标,比如<code>IM系统</code>中为了保证服务端转发消息给客户端时的消息服务质量,我借鉴了<code>TCP</code>的超时重传机制,当通过<code>channel</code>将消息推送给客户端后,达到一定的时间,服务端还没有收到客户端对该消息的<code>ack</code>消息,那么就认为该消息丢失,会触发重传,为了能够掌握某个节点的消息质量情况和超时重传队列的长度,我对重传的次数以及队列的长度都使用了<code>Metrics</code>进行监控,而为了确保在多线程环境下累加重传的次数的线程安全性,我采用了<code>AtomicLong</code>用来计算重传次数计数,<code>AtomicLong</code>称为原子变量,内部利用<code>CAS</code>指令自旋的方式来完成值的比较和更新,确保了操作的线程安全,但是其底层是如何保证的呢,保留疑问,跟随本文寻找答案</p>
<h1 id="atomiclong"><a class="markdownIt-Anchor" href="#atomiclong"></a> AtomicLong</h1>
<p>首先通过阅读Java层面的<code>AtomicLong</code>的源码,了解下它的自增实现</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AtomicLong</span> <span class="token keyword">extends</span> <span class="token class-name">Number</span> <span class="token keyword">implements</span> <span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span>Serializable</span> <span class="token punctuation">{</span>
<span class="token comment">// setup to use Unsafe.compareAndSwapLong for updates</span>
<span class="token comment">// Unsafe 提供了很多最底层的操作,此处主要是用到其内部定义的CAS相关的方法</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Unsafe</span> unsafe <span class="token operator">=</span> <span class="token class-name">Unsafe</span><span class="token punctuation">.</span><span class="token function">getUnsafe</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">long</span> valueOffset<span class="token punctuation">;</span>
<span class="token comment">// 当前机器是否支持8字节的长整型的cas操作,如果不支持,为了确保原子性的读取和写入,会使用锁的方式来操作共享变量 value,比如32位机器就是false</span>
<span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">boolean</span> <span class="token constant">VM_SUPPORTS_LONG_CAS</span> <span class="token operator">=</span> <span class="token class-name">VMSupportsCS8</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">static</span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token comment">// 获取AtomicLong类的属性value在实例数据区中的偏移量</span>
valueOffset <span class="token operator">=</span> unsafe<span class="token punctuation">.</span>objectFieldOffset
<span class="token punctuation">(</span><span class="token class-name">AtomicLong</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">getDeclaredField</span><span class="token punctuation">(</span><span class="token string">"value"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span>ex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token comment">// volatile 修饰,保证当有线程修改该变量的值对其他线程的可见性</span>
<span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token keyword">long</span> value<span class="token punctuation">;</span>
<span class="token comment">// 原子性的递增1</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">long</span> <span class="token function">getAndIncrement</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 通过unsafe来完成</span>
<span class="token keyword">return</span> unsafe<span class="token punctuation">.</span><span class="token function">getAndAddLong</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> valueOffset<span class="token punctuation">,</span> <span class="token number">1L</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>Unsafe类</p>
<pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Unsafe</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">long</span> <span class="token function">getAndAddLong</span><span class="token punctuation">(</span><span class="token class-name">Object</span> object<span class="token punctuation">,</span> <span class="token keyword">long</span> offset<span class="token punctuation">,</span> <span class="token keyword">long</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">long</span> result<span class="token punctuation">;</span>
<span class="token comment">// 通过自旋的方式给指定的属性设置值</span>
<span class="token keyword">do</span> <span class="token punctuation">{</span>
<span class="token comment">// 获取基于object对象指定offset的属性值</span>
result <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getLongVolatile</span><span class="token punctuation">(</span>object<span class="token punctuation">,</span> offset<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 比较该属性的值是否等于目标值result,如果等于,那么就更新为result + value,如果更新失败,再次重试</span>
<span class="token punctuation">}</span> <span class="token keyword">while</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">compareAndSwapLong</span><span class="token punctuation">(</span>object<span class="token punctuation">,</span> offset<span class="token punctuation">,</span> result<span class="token punctuation">,</span> result <span class="token operator">+</span> value<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// cas成功的目标值</span>
<span class="token keyword">return</span> result<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 获取对象属性的值</span>
<span class="token keyword">public</span> <span class="token keyword">native</span> <span class="token keyword">long</span> <span class="token function">getLongVolatile</span><span class="token punctuation">(</span><span class="token class-name">Object</span> object<span class="token punctuation">,</span> <span class="token keyword">long</span> fieldOffset<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// native 方法</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">native</span> <span class="token keyword">boolean</span> <span class="token function">compareAndSwapLong</span><span class="token punctuation">(</span><span class="token class-name">Object</span> var1<span class="token punctuation">,</span> <span class="token keyword">long</span> var2<span class="token punctuation">,</span> <span class="token keyword">long</span> var4<span class="token punctuation">,</span> <span class="token keyword">long</span> var6<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>可以看到<code>AtomicLong#getAndIncrement</code>方法内部直接使用了<code>Unsafe#getAndAddLong</code>方法来完成自增1的操作,在<code>unsafe</code>方法内部会一直自旋获取<code>AtomicLong</code>对象属性<code>value</code>的值,然后<code>cas</code>更新<code>value</code>,如果更新失败那么继续重试</p>
<p>上面的方法简洁明了,但是却看不到底层是如何处理的,所以为了搞清细节,继续深究源码</p>
<h1 id="读取-计算-更新"><a class="markdownIt-Anchor" href="#读取-计算-更新"></a> 读取 计算 更新</h1>
<p>在<code>CPU</code>中要对值做一个更新操作,需要经历读取值,计算值,更新值的过程,比如一个 <code>i = i + 5</code>底层会生成三条汇编指令:</p>
<pre class="line-numbers language-asm" data-language="asm"><code class="language-asm">// 读取:从内存读取地址i的值
MOV AX, iaddr
// 计算:对寄存器中的值进行加 5 操作
ADD AX, 5
// 更新:将计算后的结果写回到内存中的 i
MOV iaddr, AX <span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>如果多个线程同时对<code>i</code>进行读写操作,那么最终的结果很有可能会与预期不一致</p>
<table>
<thead>
<tr>
<th>执行时序</th>
<th>线程</th>
<th>内存 i 地址存储的值</th>
<th>读取(AX = i)</th>
<th>AX 计算</th>
<th>更新(i = AX)</th>
<th>线程状态</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>A</td>
<td>10</td>
<td>10</td>
<td></td>
<td></td>
<td><code>RUNNING</code> (context switch)</td>
</tr>
<tr>
<td>2</td>
<td>B</td>
<td>10</td>
<td>10</td>
<td>AX = 20 = AX + 10</td>
<td>i = AX = 20</td>
<td><code>RUNNING</code></td>
</tr>
<tr>
<td>3</td>
<td>A</td>
<td>20</td>
<td>10</td>
<td>AX = 15 = AX + 5</td>
<td>i = AX = 15</td>
<td><code>RUNNING</code></td>
</tr>
<tr>
<td>4</td>
<td>A</td>
<td>15</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>5</td>
<td>B</td>
<td>15</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p>可以看到表格最后<code>i</code>的值为15,<code>B线程</code>所做的更新被<code>A线程</code>覆盖,与预期的20不一致,在<code>i</code>上发生了线程安全问题,为了保证计算与更新值的结果是正确的,一般通过两种途径:</p>
<ul>
<li>对关于<code>i</code>的临界区代码加锁,确保同一时刻只有一个线程能执行临界区中的代码</li>
<li>要么通过CAS指令来自旋更新,直到更新成功</li>
</ul>
<h1 id="cas指令"><a class="markdownIt-Anchor" href="#cas指令"></a> CAS指令</h1>
<blockquote>
<p><code>CAS</code>的全称为:Compare And Swap,顾名思义就是比较目标地址的值是否与期望值相等,如果相等就把目标值更新到目标地址中</p>
</blockquote>
<p>在解析底层源码之前,先了解一下<code>cas</code>底层的指令<br />
我们常用的<code>cpu</code>一般为两种架构,分别是<code>x86</code>和<code>arm</code>,这两种架构都有各自的指令集,指令集中都定义了各自的cas指令</p>
<ul>
<li><code>X86</code>:指令复杂,性能优秀,功耗较高,广泛用于PC,服务器等领域</li>
<li><code>ARM</code>:指令精简,保证一定性能的同时,功耗表现出色,广泛用于移动端中断,嵌入式设备等领域</li>
</ul>
<h2 id="x86"><a class="markdownIt-Anchor" href="#x86"></a> X86</h2>
<blockquote>
<p>下文指令介绍来源于 Intel 开发人员手册 <a href="https://www.intel.cn/content/www/cn/zh/content-details/782158/intel-64-and-ia-32-architectures-software-developer-s-manual-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4.html?wapkw=intel%2064%20and%20ia-32%20architectures%20software%20developer%27s%20manual&docid=782158">Intel® 64 和 IA-32 架构软件开发人员手册合并卷:1、2A、2B、2C、2D、3A、3B、3C、3D 和 4</a></p>
</blockquote>
<p>在X86中,定义了指令<code>CMPXCHG</code>,它的基本功能是比较EAX寄存器的值和指定内存地址的值,如果相等,则将内存地址中的值替换为指定操作数的值,如果不相等,则将内存地址中的值加载到EAX寄存器中</p>
<ul>
<li><code>CMPXCHG</code>指令原型:<code>CMPXCHG address, new_value</code>
<ul>
<li>将比较值放入<code>EAX</code>寄存器的指令要先于<code>CMPXCHG</code>指令之前定义:<code>MOV EAX, expected_value</code></li>
</ul>
</li>
</ul>
<p>可以看到,<code>CMPXCHG</code> 指令将值的读取和比较更新分为了两步,先需要将目标地址的期望值放入<code>EAX</code>寄存器,再来执行<code>CMPXCHG</code>指令完成比较并交换的操作,因此只是保证了<strong>比较和更新</strong>操作的原子性,不能保证读取到的数据一定是最新的,所以会出现CAS失败的情况,因此上层需要通过自旋来执行CAS操作,确保能够完成更新。</p>
<p>我们通过<code>CMPXCHG</code>指令可以完成比较值和更新值的原子性,但如果只通过该指令就能完成原子操作了吗,显然没有这么简单,听我细细道来</p>
<h2 id="cpu-缓存"><a class="markdownIt-Anchor" href="#cpu-缓存"></a> CPU 缓存</h2>
<blockquote>
<p>详细了解<code>CPU</code>缓存体系可移步这篇博客 <a href="/posts/1a5fbe08.html">CPU缓存与MESI协议</a></p>
<ul>
<li>下面的内容大部分来源于该博客</li>
</ul>
</blockquote>
<p><code>cpu</code>在将数据写入到目标地址之前,需要将数据先从内存读取到<code>L1数据缓存</code>,再从<code>L1数据缓存</code>读取到<code>寄存器</code>中,经过<code>ALU</code>计算,再通过<code>mov</code>系列指令把数据拷贝到目标地址,但此时只是写入<code>L1数据缓存</code>,而<code>L1数据缓存</code>它是<code>cpu</code>私有的,那么在多cpu环境下(<em>假设每个cpu只有一个核</em>),如果没有额外的手段,就会造成<code>cpu A</code>对地址<code>A</code>的值的更新操作是对其他<code>cpu</code>是不可见的,因为此时最新的数据只是在它自己的<code>L1私有数据缓存</code>中,对于这个问题,聪明的<code>cpu</code>设计师当然给出了解决办法</p>
<h3 id="lock-指令"><a class="markdownIt-Anchor" href="#lock-指令"></a> Lock# 指令</h3>
<blockquote>
<p>关于Intel 开发人员手册 对 Lock# 指令的介绍可以查阅下面的文章</p>
<ul>
<li>– 卷2 Chapter 3.3 LOCK—Assert LOCK# Signal Prefix 1213 页</li>
<li>– 卷3 Chapter 10.1 Locked Atomic Operations 3368页<br />
下面的内容大部分来自于该手册</li>
</ul>
</blockquote>
<p>Intel 为<code>cpu</code>提供了 Lock# 指令,将该指令与特定指令结合使用可以保证多个<code>CPU</code>对目标共享地址的操作是互斥的,因为Lock 指令需要和其他指令结合使用因此也称为 <code>Lock 锁前缀</code></p>
<p>在早期的Intel cpu中(<em>如Pentium</em>),Lock 锁前缀指令总是会通过总线仲裁器来锁定总线,保证了特定的指令在执行时是原子的以及多处理器环境下读写目标地址数据的一致性,防止其他<code>CPU</code>同时访问或修改同一内存地址的数据,但这种方式会导致其他Cpu在总线锁定的期间,因为处理器无法使用总线去访问内存而导致的阻塞(stall),导致了性能的急剧降低,因此在<code>P6</code>以及后续Intel处理器中,增加了<code>缓存行锁定</code>技术来解决因总线锁定而导致的性能瓶颈</p>
<h4 id="总线仲裁器"><a class="markdownIt-Anchor" href="#总线仲裁器"></a> 总线仲裁器</h4>
<p>在介绍下面的概念之前,我想先介绍一个重要的硬件单元<code>总线仲裁器</code>,总线仲裁器它连接了所有设备所访问的总线,包括地址总线,数据总线,控制总线,它管理多个设备对共享总线的访问请求,确保在同一时间只有一个设备能够访问总线,从而避免数据冲突和不一致性</p>
<ul>
<li><code>地址总线(Address Bus)</code>:用于指定数据传输的目标地址</li>
<li><code>数据总线(Data Bus)</code>:用于数据的传输</li>
<li><code>控制总线</code>:用于传输控制信号,如读写命令,中断请求等</li>
</ul>
<p>工作流程</p>
<ol>
<li>接受请求:接收来自各个设备(如cpu,dma控制器,i/o设备等)的总线访问请求</li>
<li>分配总线使用权:根据某种算法(如固定优先级,轮询等)决定哪个设备获得总线的使用权</li>
<li>释放总线使用权:当设备完成数据传输后,释放总线使用权,允许其他设备访问总线</li>
</ol>
<h4 id="总线锁定"><a class="markdownIt-Anchor" href="#总线锁定"></a> 总线锁定</h4>
<p>介绍一下总线锁定的流程,以理解为什么能保证指令执行的原子性和读写数据的一致性,性能瓶颈发生的原因</p>
<ol>
<li>CPU在执行<code>lock</code> 前缀指令时,会使能总线锁定引脚(Lock#),向总线仲裁器发送电信号,该信号伴随当前总线周期(如内存读/写操作)持续有效,直至操作完成</li>
<li>总线仲裁器检测到<code>Lock</code>信号,会冻结当前请求仲裁队列,暂停处理其他设备的总线请求,确保当前CPU的操作不受干扰,阻止其他设备抢占总线</li>
<li>在<code>Lock</code>有效期间,CPU完全独占总线可以安全的对共享内存执行读写操作</li>
<li>CPU完成<code>Lock</code>指令后,撤销<code>Lock</code>信号,总线仲裁器恢复正常工作,其他设备此时可以竞争访问总线</li>
</ol>
<p>可以看到整个流程,总线锁定需要一直等待<code>lock</code>指令的执行完成才能释放总线,在此期间,所有设备都无法访问总线,可想而知对性能的影响有多大</p>
<h4 id="缓存行锁定"><a class="markdownIt-Anchor" href="#缓存行锁定"></a> 缓存行锁定</h4>
<blockquote>
<p>下面内容都来源下面这篇博客,此处为了该篇博客的完整性,提供对缓存行以及相关概念的简要说明,详细细节请看:</p>
<ul>
<li><a href="/posts/1a5fbe08.html">CPU缓存与MESI协议</a></li>
</ul>
</blockquote>
<h5 id="缓存结构"><a class="markdownIt-Anchor" href="#缓存结构"></a> 缓存结构</h5>
<p>处理器在访问内存时通常需要100到300个周期,这意味着在这个访存周期中,cpu只能干等着内存控制器将数据响应给cpu,为了提高效率,弥补处理器与内存之间的差距,因此在处理器与内存之间增加了缓存结构,分为<code>L1</code>,<code>L2</code>,<code>L3</code>三级缓存,<code>L1缓存</code>和<code>L2缓存</code>是<code>cpu核心</code>私有,而<code>L3</code>缓存则属于同一个<code>cpu</code>的核心共享,越靠近cpu的速度也就越快,但是可存储的容量也越小</p>
<h5 id="缓存行状态"><a class="markdownIt-Anchor" href="#缓存行状态"></a> 缓存行状态</h5>
<p>不管是L1,L2,L3缓存,其缓存行的状态都会在<code>Modified</code>,<code>Exclusive</code>,<code>Shared</code>,<code>Invalidate</code>四个状态中切换</p>
<ul>
<li><code>Modified</code>:当前缓存行中的副本数据已被修改,意味着内存中的数据是过期的</li>
<li><code>Exclusive</code>:处于该状态的缓存行表示只存在当前cpu的缓存中,并且与内存中的副本相同</li>
<li><code>Shared</code>:处于该状态的缓存行意味着同时也存在其他cpu的缓存中,并且与内存中的副本相同</li>
<li><code>Invalidate</code>:处于该状态的缓存行表示是失效状态无法访问,需要重新执行缓存行填充</li>
</ul>
<h5 id="内存目录"><a class="markdownIt-Anchor" href="#内存目录"></a> 内存目录</h5>
<p>内存目录是多核处理器系统中用于高效管理缓存一致性的关键硬件结构,它通过记录内存块<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>在各级缓存中的状态和位置,减少了传统<code>侦听</code>(<em>Snooping</em>)协议中的广播开销</p>
<ul>
<li>如果没有内存目录记录内存块的信息,那么根据传统<code>侦听协议</code>的处理,需要在总线上广播请求,缓存了该内存块的<code>cpu</code>收到请求后则给出响应,没有则访问主存</li>
</ul>
<blockquote>
<p>内存目录通常集成在内存控制器或者是L3缓存中</p>
</blockquote>
<p>内存目录的作用就是对缓存状态进行跟踪,它会记录每个内存块(缓存行)的缓存副本分布在哪些<code>cpu</code>中,以及在这些<code>cpu</code>缓存中的状态,通过精确的目录信息,避免向所有<code>cpu</code>广播请求,仅发送给持有有效状态缓存的<code>cpu</code>,减少了无效的总线侦听流量</p>
<h5 id="缓存状态的维护"><a class="markdownIt-Anchor" href="#缓存状态的维护"></a> 缓存状态的维护</h5>
<p>缓存行的状态是由缓存一致性<code>MESI</code>协议维护,当某个<code>cpu</code>核心想要写入某个地址的数据时,必须要在L1缓存中持有该内存块的缓存行,并且缓存行状态必须为<code>E</code>或<code>M</code>的,如果是其他状态(<code>R</code>或者<code>I</code>)或者没有未在缓存行命中,那么就需要通过额外的方式来获取对该地址的可修改权力,如果有<code>cpu</code>,这是缓存一致性协议为了保证多核之间的缓存数据的一致性所规定的</p>
<h5 id="cpu-读取内存数据流程"><a class="markdownIt-Anchor" href="#cpu-读取内存数据流程"></a> cpu 读取内存数据流程</h5>
<p>cpu在读取内存数据时,首先会检查最近的L1缓存,如果命中就直接返回,未命中则向下查询L2缓存,如果L2缓存命中,那么返回数据并写入L1缓存,未命中,继续查询L3缓存,如果命中,返回数据并写入L2缓存和L1缓存,如果未命中,那么会通过向内存控制器发送<code>BusRead</code>请求,内存控制器会检查内存目录,查看该地址的数据是否被其他cpu缓存,如果是,则在总线上广播请求,持有了该地址缓存行的<code>cpu</code>会响应数据,如果状态是M,根据<code>缓存一致性协议</code>,那么需要将缓存行的数据写入主存,并将状态修改为S,如果其他<code>cpu</code>的缓存中没有该地址的数据,则内存控制器需要访问主存,并通过预取技术读取包含该目标地址前后的64个字节,然后将数据按顺序从主存填充到L3,并且同时触发L2和L1的<code>级联填充</code>,数据写入各自的缓存</p>
<h5 id="cpu-写入内存数据流程"><a class="markdownIt-Anchor" href="#cpu-写入内存数据流程"></a> cpu 写入内存数据流程</h5>
<p>cpu 将数据写入目标内存地址之前,首先会检查是否持有该目标内存地址的缓存行,如果持有,并且状态是<code>E</code>,那么直接写入,并且更改缓存行状态为<code>M</code>,</p>
<h3 id="arm"><a class="markdownIt-Anchor" href="#arm"></a> ARM</h3>
<hr class="footnotes-sep" />
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>内存块通常对应一个缓存行 <a href="#fnref1" class="footnote-backref">↩︎</a></p>
</li>
</ol>
</section>
]]></content>
<categories>
<category>源码分析</category>
<category>hotspot</category>
</categories>
<tags>
<tag>源码</tag>
<tag>JVM</tag>
</tags>
</entry>
<entry>
<title>JMM</title>
<url>/posts/cff6dd61.html</url>
<content><![CDATA[<h3 id="引言"><a class="markdownIt-Anchor" href="#引言"></a> 引言</h3>
<p>在Java这个世界中,如果把JVM比作一个运行java代码的生态土壤,那么JMM就是Java中的生态法则,它规定了这个世界的运行规则,定义了线程本地的变量读取存储,多线程之间的变量共享规则,并屏蔽了底层不同cpu架构,系统之间的差别,我们只需要遵守规范便可以开发出稳定可靠的单/多线程应用</p>
<h3 id="介绍"><a class="markdownIt-Anchor" href="#介绍"></a> 介绍</h3>
<p><a href="https://docs.oracle.com/javase/specs/jls/se23/html/jls-17.html#jls-17.4"><code>JMM(Java Memory Model)</code></a>:是 Java 语言规范定义的一组规则,用于协调多线程之间的内存访问操作,保证多线程程序在不同的硬件和操作系统平台上都能正确地执行。下面从几个方面对 JMM 进行完整的描述:</p>
<h4 id="基本概念"><a class="markdownIt-Anchor" href="#基本概念"></a> 基本概念</h4>
<p><code>主内存 (Main Memory)</code>: 主内存是所有线程共享的内存区域,它存储了Java的对象,静态变量,类信息,常量池信息<br />
<code>工作内存(Working Memory)</code>: 每个线程都有自己独立的工作内存,它是线程私有的,线程在执行过程中,会将主内存的数据拷贝到自己的工作内存,操作完成后再将结果写回主内存</p>
<blockquote>
<p>定义上面的概念是解决不同平台以及不同硬件架构下的内存交互约束,在具体实现上主内存可以看作是RAM,而工作内存看作是寄存器,CPU缓存以及局部变量表(这个是栈帧中的一块区域,这块区域的大小编译期就可以确定下来)</p>
</blockquote>
<h4 id="工作内存之局部变量表"><a class="markdownIt-Anchor" href="#工作内存之局部变量表"></a> 工作内存之局部变量表</h4>
<p>局部变量表是栈帧中开辟的一块确定大小的连续内存区域,用于存放方法中使用到的变量</p>
<p><<<<<<< HEAD</p>
<blockquote>
<p>如果对局部变量表是如何在栈帧中创建感兴趣,可以在这篇博客找到答案 <a href="/posts/48bea92d.html">Hotspot源码剖析Java方法执行流程</a></p>
</blockquote>
<h4 id="编译优化"><a class="markdownIt-Anchor" href="#编译优化"></a> 编译优化</h4>
<p>Java的字节码通常是由解释器和编译器相互配合执行的,为了让Java应用能够更快速的启动通常是解释器先发挥作用,逐行解释字节码指令转换成为对应平台的</p>
<p>=======<br />
<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>jdk8u hotspot <code>CppInterpreter.cpp</code> 是一个c++编写的字节码解释器,其中编写了如何关联局部变量表以及解释执行字节码指令的代码,接下来让我们看源码来了解方法的执行过程以及字节码解释执行的流程</p>
<ol>
<li>执行java方法的入口</li>
</ol>
<pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">int CppInterpreter::normal_entry(Method* method, intptr_t UNUSED, TRAPS) {
JavaThread *thread = (JavaThread *) THREAD;
// Allocate and initialize our frame.
// 为方法分配并初始化栈帧,其内部就会创建我们的局部变量表,以及设置bcp指针
InterpreterFrame *frame = InterpreterFrame::build(method, CHECK_0);
// 保存我们的栈帧到线程栈中
thread->push_zero_frame(frame);
// Execute those bytecodes!
// 进入执行字节码的主入口
main_loop(0, THREAD);
// No deoptimized frames on the stack
return 0;
}
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<ol start="2">
<li>构建方法栈帧</li>
</ol>
<pre class="line-numbers language-c++" data-language="c++"><code class="language-c++">InterpreterFrame *InterpreterFrame::build(Method* const method, TRAPS) {
JavaThread *thread = (JavaThread *) THREAD;
ZeroStack *stack = thread->zero_stack();
// Calculate the size of the frame we'll build, including
// any adjustments to the caller's frame that we'll make.
// 方法内部局部变量数量
int extra_locals = 0;
// 监视器占用空间大小
int monitor_words = 0;
// 局部变量表变量个数/长度
int stack_words = 0;
// 注意,上面的参数编译期就可以确定下来,可以通过javap -l .class 看到局部变量表信息
// 所以这里只是取出来然后分配一个大小合适的局部变量表来存储方法中所操作的变量
if (!method->is_native()) {
// 局部变量表长度 - 方法参数 得到 方法内部定义的局部变量个数
extra_locals = method->max_locals() - method->size_of_parameters();
// 局部变量表solt个数
stack_words = method->max_stack();
}
if (method->is_synchronized()) {
// 方法是同步的,那么需要分配一个solt存储
monitor_words = frame::interpreter_frame_monitor_size();
}
// 检查是否栈溢出
stack->overflow_check(
extra_locals + header_words + monitor_words + stack_words, CHECK_NULL);
// Adjust the caller's stack frame to accomodate any additional
// local variables we have contiguously with our parameters.
// push() -> *(--sp) = value 栈扩容(在操作系统里,栈的增长是向低地址增长的,而数据段是向上扩容的),预先占用局部变量的空间
for (int i = 0; i < extra_locals; i++)