Время от времени вы смотрите на некоторый код и думаете, что он не может быть ошибочным. После того, как вы исключили простое программистское искажение / вражеское действие в коде (убедитесь, что вы читаете Java Puzzlers или аналогичные) или проблему с параллелизмом (прочитайте Java Concurrency или изучите превосходный курс Dr Heniz ), вам следует бездельничать и занять несколько дней. и затем начинаю думать о том, действительно ли JDK хочет тебя достать. Я не видел никого в дикой природе за свои 18 с лишним лет как программист на Java, так что это застало меня врасплох.
Если вы работаете с JDK 8 в крупномасштабном Swing-приложении, вы можете в конечном итоге увидеть следующее исключение, много раз. (Если вы не забыли урок, полученный в моем предыдущем блоге, в своем коде регистрации, в этом случае вы можете увидеть много ArrayOfOutBoundsException)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
Caused by: java.lang.NullPointerException at javax.swing.text.GlyphView.getBreakSpot(GlyphView.java: 799 ) at javax.swing.text.GlyphView.getBreakWeight(GlyphView.java: 724 ) at javax.swing.text.FlowView$LogicalView.getPreferredSpan(FlowView.java: 733 ) at javax.swing.text.FlowView.calculateMinorAxisRequirements(FlowView.java: 233 ) at javax.swing.text.ParagraphView.calculateMinorAxisRequirements(ParagraphView.java: 717 ) at javax.swing.text.BoxView.checkRequests(BoxView.java: 935 ) at javax.swing.text.BoxView.getMinimumSpan(BoxView.java: 568 ) at javax.swing.text.BoxView.calculateMinorAxisRequirements(BoxView.java: 903 ) at javax.swing.text.BoxView.checkRequests(BoxView.java: 935 ) at javax.swing.text.BoxView.setSpanOnAxis(BoxView.java: 343 ) at javax.swing.text.BoxView.layout(BoxView.java: 708 ) at javax.swing.text.BoxView.setSize(BoxView.java: 397 ) ... |
Эта ошибка особенно коварна, потому что требуется около десяти минут, чтобы показать себя, а иногда и вовсе. Если вы посмотрите на код для этого класса, то рассматриваемая строка, начинающаяся с «setsFrom = break», получает доступ только к двум локальным переменным, на обе из которых ранее ссылались в методе.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
Segment s = getText(pstart, pend); s.first(); BreakIterator breaker = getBreaker(); breaker.setText(s); // Backward search should start from end+1 unless there's NO end+1 int startFrom = end + (pend > end ? 1 : 0 ); for (;;) { startFrom = breaker.preceding(s.offset + (startFrom - pstart)) + (pstart - s.offset); if (startFrom > start) { // The break spot is within the view bs[ix++] = startFrom; } else { break ; } } |
Самый прямой способ исключить ошибку JIT — отключить компиляцию только для этого единственного метода, вот пример; но вы можете узнать больше в документации по Java-инструменту командной строки .
1
|
javaThing -XX:CompileCommand=exclude,javax/swing/text/GlyphView,getBreakSpot |
Когда этот параметр добавлен, проблема исчезнет. — поскольку мы исключили действия противника с помощью кода или проблемы параллелизма, мы можем быть более уверены, что это проблема JIT. Теперь, как часть регистрации ошибок, я вывел диагностику для этого единственного метода и обнаружил, что проблема не возникала, пока метод не был JITted в пятый раз.
1
|
javaThing -XX:CompileCommand=print,javax/swing/text/GlyphView,getBreakSpot |
Вот некоторые диагностические результаты, показанные с помощью приведенной выше команды:
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
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
|
Compiled method (c2) 914078 33142 4 javax.swing.text.GlyphView::getBreakSpot ( 247 bytes) total in heap [ 0x00002aaab0749e10 , 0x00002aaab0750fe0 ] = 29136 relocation [ 0x00002aaab0749f38 , 0x00002aaab074a1e8 ] = 688 constants [ 0x00002aaab074a200 , 0x00002aaab074a2a0 ] = 160 main code [ 0x00002aaab074a2a0 , 0x00002aaab074cde0 ] = 11072 stub code [ 0x00002aaab074cde0 , 0x00002aaab074ce40 ] = 96 oops [ 0x00002aaab074ce40 , 0x00002aaab074ce58 ] = 24 metadata [ 0x00002aaab074ce58 , 0x00002aaab074d058 ] = 512 scopes data [ 0x00002aaab074d058 , 0x00002aaab074ea20 ] = 6600 scopes pcs [ 0x00002aaab074ea20 , 0x00002aaab0750c50 ] = 8752 dependencies [ 0x00002aaab0750c50 , 0x00002aaab0750c80 ] = 48 handler table [ 0x00002aaab0750c80 , 0x00002aaab0750e90 ] = 528 nul chk table [ 0x00002aaab0750e90 , 0x00002aaab0750fe0 ] = 336 OopMapSet contains 113 OopMaps # 0 OopMap{[ 8 ]=Oop [ 32 ]=Oop [ 40 ]=Oop off= 892 } # 1 OopMap{[ 32 ]=Oop [ 40 ]=Oop off= 960 } # 2 OopMap{[ 32 ]=Oop [ 40 ]=Oop off= 980 } # 3 OopMap{[ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop off= 1048 } # 4 OopMap{[ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop off= 1084 } # 5 OopMap{[ 0 ]=Oop [ 24 ]=Oop [ 48 ]=Oop [ 56 ]=Oop [ 80 ]=Oop off= 2500 } # 6 OopMap{rbx=Oop rdi=Oop [ 32 ]=Oop [ 40 ]=Oop [ 112 ]=Oop off= 2533 } # 7 OopMap{rbx=Oop rdi=Oop r14=Oop [ 32 ]=Oop [ 112 ]=Oop off= 3081 } # 8 OopMap{rbx=Oop rdi=Oop r14=Oop [ 32 ]=Oop [ 40 ]=Oop [ 112 ]=Oop off= 3190 } # 9 OopMap{[ 8 ]=Oop [ 32 ]=Oop [ 40 ]=Oop off= 4408 } # 10 OopMap{[ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop off= 4640 } # 11 OopMap{rbp=Oop [ 16 ]=Oop [ 24 ]=Oop [ 40 ]=Oop [ 64 ]=Oop off= 5232 } # 12 OopMap{rbp=Oop [ 0 ]=NarrowOop [ 32 ]=Oop off= 5364 } # 13 OopMap{[ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop off= 5408 } # 14 OopMap{rbp=Oop [ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop off= 5436 } # 15 OopMap{rbp=Oop [ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop off= 5468 } # 16 OopMap{rbp=Oop [ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop off= 5524 } # 17 OopMap{rbp=Oop [ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop [ 88 ]=Oop off= 5552 } # 18 OopMap{[ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop [ 64 ]=Oop [ 72 ]=Derived_oop_[ 64 ] [ 112 ]=Oop off= 5608 } # 19 OopMap{[ 8 ]=Oop [ 32 ]=Oop off= 5680 } # 20 OopMap{rbp=Oop off= 5720 } # 21 OopMap{rbp=Oop off= 5752 } # 22 OopMap{rbp=Oop [ 24 ]=NarrowOop [ 28 ]=NarrowOop [ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop [ 56 ]=Oop [ 64 ]=Oop [ 88 ]=Oop off= 5812 } # 23 OopMap{rbp=Oop [ 16 ]=Oop [ 24 ]=Oop [ 40 ]=Oop [ 64 ]=Oop [ 88 ]=Oop off= 5960 } # 24 OopMap{[ 0 ]=Oop [ 24 ]=Oop [ 48 ]=Oop [ 56 ]=Oop [ 72 ]=Oop [ 88 ]=NarrowOop off= 6056 } # 25 OopMap{[ 40 ]=Oop off= 6088 } # 26 OopMap{[ 0 ]=Oop off= 6120 } # 27 OopMap{[ 8 ]=Oop [ 24 ]=Oop [ 56 ]=Oop [ 72 ]=Oop [ 112 ]=Oop off= 6216 } # 28 OopMap{[ 0 ]=Oop [ 32 ]=NarrowOop [ 40 ]=Oop off= 6284 } # 29 OopMap{rbp=Oop [ 16 ]=Oop [ 40 ]=Oop [ 64 ]=Oop [ 112 ]=Oop off= 6384 } # 30 OopMap{[ 0 ]=Oop off= 6412 } # 31 OopMap{[ 0 ]=Oop [ 16 ]=Oop [ 32 ]=NarrowOop [ 40 ]=Oop [ 48 ]=Oop off= 6488 } # 32 OopMap{rbp=Oop [ 16 ]=Oop [ 40 ]=Oop [ 48 ]=Oop off= 6560 } # 33 OopMap{[ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop [ 64 ]=Oop [ 112 ]=Oop off= 6608 } # 34 OopMap{[ 8 ]=Oop [ 28 ]=NarrowOop [ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop off= 6768 } # 35 OopMap{rbp=NarrowOop [ 0 ]=Oop [ 16 ]=Oop [ 32 ]=Oop [ 40 ]=NarrowOop off= 6860 } # 36 OopMap{[ 0 ]=Oop [ 16 ]=Oop [ 32 ]=NarrowOop [ 40 ]=Oop [ 48 ]=Oop off= 6988 } # 37 OopMap{rbp=Oop [ 32 ]=Oop off= 7024 } # 38 OopMap{rbp=NarrowOop [ 0 ]=Oop [ 24 ]=Oop [ 32 ]=Oop off= 7260 } # 39 OopMap{rbp=NarrowOop [ 0 ]=Oop [ 24 ]=Oop [ 32 ]=Oop off= 7344 } # 40 OopMap{rbp=Oop [ 16 ]=Oop [ 24 ]=Oop [ 40 ]=Oop [ 60 ]=NarrowOop [ 64 ]=Oop off= 7452 } # 41 OopMap{rbp=NarrowOop [ 32 ]=Oop off= 7476 } # 42 OopMap{rbp=NarrowOop [ 0 ]=Oop off= 7524 } # 43 OopMap{[ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop off= 7588 } # 44 OopMap{[ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop off= 7616 } # 45 OopMap{[ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop off= 7632 } # 46 OopMap{rbp=NarrowOop [ 32 ]=Oop off= 7676 } # 47 OopMap{rbp=NarrowOop [ 0 ]=Oop off= 7724 } # 48 OopMap{[ 0 ]=Oop [ 16 ]=Oop [ 28 ]=NarrowOop [ 40 ]=Oop [ 48 ]=Oop [ 56 ]=NarrowOop [ 64 ]=Oop off= 7868 } # 49 OopMap{[ 8 ]=Oop [ 28 ]=NarrowOop [ 32 ]=Oop [ 40 ]=Oop [ 48 ]=Oop [ 56 ]=Oop off= 7916 } # 50 OopMap{rbp=Oop [ 16 ]=Oop [ 24 ]=NarrowOop off= 8016 } # 51 OopMap{rbp=Oop [ 16 ]=Oop [ 28 ]=NarrowOop off= 8080 } # 52 OopMap{rbp=NarrowOop [ 0 ]=Oop [ 24 ]=Oop [ 32 ]=Oop off= 8152 } # 53 OopMap{rbp=Oop [ 8 ]=NarrowOop off= 8212 } # 54 OopMap{rbp=NarrowOop [ 32 ]=Oop off= 8236 } # 55 OopMap{rbp=Oop [ 16 ]=NarrowOop off= 8272 } # 56 OopMap{rbp=NarrowOop [ 0 ]=Oop off= 8320 } # 57 OopMap{rbp=Oop [ 12 ]=NarrowOop off= 8360 } # 58 OopMap{rbp=NarrowOop [ 32 ]=Oop off= 8400 } # 59 OopMap{rbp=Oop [ 12 ]=NarrowOop off= 8460 } # 60 OopMap{rbp=NarrowOop [ 0 ]=Oop off= 8508 } # 61 OopMap{rbp=Oop [ 24 ]=NarrowOop [ 40 ]=Oop off= 8572 } # 62 OopMap{rbp=Oop off= 8600 } # 63 OopMap{rbp=Oop [ 8 ]=Oop [ 28 ]=NarrowOop off= 8640 } # 64 OopMap{rbp=Oop [ 8 ]=Oop [ 20 ]=NarrowOop [ 112 ]=Oop off= 8704 } # 65 OopMap{rbp=Oop [ 16 ]=Oop [ 24 ]=Oop [ 48 ]=Oop off= 8788 } # 66 OopMap{rbp=Oop [ 16 ]=Oop [ 24 ]=Oop [ 40 ]=Oop [ 64 ]=Oop off= 8912 } # 67 OopMap{rbp=Oop [ 16 ]=Oop [ 24 ]=Oop [ 40 ]=Oop [ 64 ]=Oop off= 9036 } # 68 OopMap{rbp=Oop [ 16 ]=Oop [ 24 ]=Oop [ 40 ]=Oop [ 64 ]=Oop off= 9160 } # 69 OopMap{rbp=Oop [ 16 ]=Oop [ 24 ]=Oop [ 40 ]=Oop [ 64 ]=Oop off= 9284 } # 70 OopMap{rbp=Oop [ 16 ]=Oop [ 24 ]=Oop [ 40 ]=Oop [ 64 ]=Oop off= 9408 } # 71 OopMap{rbp=Oop [ 16 ]=Oop [ 24 ]=Oop [ 40 ]=Oop [ 64 ]=Oop off= 9532 } # 72 OopMap{off= 9556 } # 73 OopMap{off= 9580 } # 74 OopMap{off= 9604 } # 75 OopMap{[ 112 ]=Oop off= 9628 } # 76 OopMap{rbp=Oop [ 8 ]=Oop [ 24 ]=Oop [ 32 ]=NarrowOop off= 9696 } # 77 OopMap{rbp=Oop [ 8 ]=Oop [ 24 ]=NarrowOop off= 9760 } # 78 OopMap{off= 9784 } # 79 OopMap{off= 9812 } # 80 OopMap{off= 9836 } # 81 OopMap{off= 9860 } # 82 OopMap{off= 9884 } # 83 OopMap{off= 9908 } # 84 OopMap{off= 9932 } # 85 OopMap{off= 9956 } # 86 OopMap{off= 9980 } # 87 OopMap{off= 10004 } # 88 OopMap{off= 10028 } # 89 OopMap{rbp=Oop [ 16 ]=Oop [ 28 ]=NarrowOop off= 10092 } # 90 OopMap{rbp=Oop [ 16 ]=Oop [ 24 ]=Oop [ 48 ]=Oop off= 10176 } # 91 OopMap{off= 10200 } # 92 OopMap{off= 10224 } # 93 OopMap{off= 10248 } # 94 OopMap{off= 10272 } # 95 OopMap{off= 10296 } # 96 OopMap{off= 10320 } # 97 OopMap{off= 10344 } # 98 OopMap{off= 10368 } # 99 OopMap{off= 10392 } # 100 OopMap{off= 10416 } # 101 OopMap{off= 10440 } # 102 OopMap{off= 10464 } # 103 OopMap{off= 10488 } # 104 OopMap{off= 10512 } # 105 OopMap{off= 10536 } # 106 OopMap{off= 10560 } # 107 OopMap{off= 10584 } # 108 OopMap{off= 10608 } # 109 OopMap{off= 10632 } # 110 OopMap{off= 10656 } # 111 OopMap{off= 10680 } # 112 OopMap{off= 11028 } java.lang.NullPointerException at javax.swing.text.GlyphView.getBreakSpot(GlyphView.java: 799 ) at javax.swing.text.GlyphView.getBreakWeight(GlyphView.java: 724 ) at javax.swing.text.html.InlineView.getBreakWeight(InlineView.java: 150 ) at javax.swing.text.FlowView$LogicalView.getPreferredSpan(FlowView.java: 733 ) at javax.swing.text.FlowView.calculateMinorAxisRequirements(FlowView.java: 233 ) at javax.swing.text.ParagraphView.calculateMinorAxisRequirements(ParagraphView.java: 717 ) at javax.swing.text.html.ParagraphView.calculateMinorAxisRequirements(ParagraphView.java: 157 ) at javax.swing.text.BoxView.checkRequests(BoxView.java: 935 ) at javax.swing.text.BoxView.getMinimumSpan(BoxView.java: 568 ) at javax.swing.text.html.ParagraphView.getMinimumSpan(ParagraphView.java: 270 ) at javax.swing.text.BoxView.calculateMinorAxisRequirements(BoxView.java: 903 ) |
Сейчас я все еще работаю с командой JDK для исправления этой проблемы; но я чувствую, что обнаружил полезный набор инструментов для предоставления некоторых доказательств того, что JIT-компилятор вызывает мой плохой день. И что более важно, у меня есть обходной путь, чтобы я мог запускать свои тесты, пока это не будет решено.