-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
525 lines (445 loc) · 112 KB
/
atom.xml
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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[测试小站]]></title>
<subtitle><![CDATA[如果方向错了,停下来就是前进。]]></subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://yoursite.com/"/>
<updated>2019-02-17T09:29:55.221Z</updated>
<id>http://yoursite.com/</id>
<author>
<name><![CDATA[觅不凡]]></name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title><![CDATA[python变量交换]]></title>
<link href="http://yoursite.com/2019/02/17/PySwap/"/>
<id>http://yoursite.com/2019/02/17/PySwap/</id>
<published>2019-02-17T08:48:11.582Z</published>
<updated>2019-02-17T09:29:55.221Z</updated>
<content type="html"><![CDATA[<p>python数值交换不推荐使用中间值,使用Pythonic的实现不仅简洁,而且执行效率高。<br><a id="more"></a></p>
<h2 id="中间值方法">中间值方法</h2><p>交换两个变量的值,我们熟悉的方法如下:<br><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">temp</span> = x</span><br><span class="line"><span class="attr">x</span> = y</span><br><span class="line"><span class="attr">y</span> = temp</span><br></pre></td></tr></table></figure></p>
<h2 id="Pythonic_实现方式">Pythonic 实现方式</h2><p>python中有Pythonic的实现方式:<br><figure class="highlight llvm"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">x</span>, y = y, <span class="keyword">x</span></span><br></pre></td></tr></table></figure></p>
<h2 id="交换效率">交换效率</h2><p>我们使用timeit查看下两则的交换效率<br><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">>></span>> from timeit import Timer</span><br><span class="line"><span class="meta">>></span>> Timer(<span class="string">"x, y = y, x"</span>, <span class="string">"x=2;y=3"</span>).timeit()</span><br><span class="line"><span class="number">0</span>.<span class="number">05177</span>9985427856445</span><br><span class="line"><span class="meta">>></span>> Timer(<span class="string">"temp=x;x=y;y=temp"</span>, <span class="string">"x=2; y=3"</span>).timeit()</span><br><span class="line"><span class="number">0</span>.<span class="number">06303</span>882598876953</span><br></pre></td></tr></table></figure></p>
<p>可以看到Pythonic的实现不仅简洁,而且执行效率高</p>
<h2 id="dis分析">dis分析</h2><p>使用dis分析python执行的字节码:<br><figure class="highlight flix"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> dis</span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">swap1</span></span>():</span><br><span class="line"> x, y = <span class="number">2</span>, <span class="number">3</span></span><br><span class="line"> x, y = y, x</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">swap2</span></span>():</span><br><span class="line"> x, y = <span class="number">2</span>, <span class="number">3</span></span><br><span class="line"> temp = x</span><br><span class="line"> x = y</span><br><span class="line"> y = temp</span><br><span class="line"></span><br><span class="line">dis.dis(swap1)</span><br><span class="line">dis.dis(swap2)</span><br></pre></td></tr></table></figure></p>
<p>结果分别如下:<br><figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">>>> dis.dis(swap1)</span><br><span class="line"> <span class="number">2</span> <span class="number">0</span> LOAD_CONST <span class="number">3</span> ((<span class="number">2</span>, <span class="number">3</span>))</span><br><span class="line"> <span class="number">3</span> UNPACK_SEQUENCE <span class="number">2</span></span><br><span class="line"> <span class="number">6</span> STORE_FAST <span class="number">0</span> (x)</span><br><span class="line"> <span class="number">9</span> STORE_FAST <span class="number">1</span> (y)</span><br><span class="line"></span><br><span class="line"> <span class="number">3</span> <span class="number">12</span> LOAD_FAST <span class="number">1</span> (y)</span><br><span class="line"> <span class="number">15</span> LOAD_FAST <span class="number">0</span> (x)</span><br><span class="line"> <span class="number">18</span> ROT_TWO </span><br><span class="line"> <span class="number">19</span> STORE_FAST <span class="number">0</span> (x)</span><br><span class="line"> <span class="number">22</span> STORE_FAST <span class="number">1</span> (y)</span><br><span class="line"> <span class="number">25</span> LOAD_CONST <span class="number">0</span> (None)</span><br><span class="line"> <span class="number">28</span> RETURN_VALUE</span><br></pre></td></tr></table></figure></p>
<figure class="highlight lsl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">>>> dis.dis(swap2)</span><br><span class="line"> <span class="number">2</span> <span class="number">0</span> LOAD_CONST <span class="number">3</span> ((<span class="number">2</span>, <span class="number">3</span>))</span><br><span class="line"> <span class="number">3</span> UNPACK_SEQUENCE <span class="number">2</span></span><br><span class="line"> <span class="number">6</span> STORE_FAST <span class="number">0</span> (x)</span><br><span class="line"> <span class="number">9</span> STORE_FAST <span class="number">1</span> (y)</span><br><span class="line"></span><br><span class="line"> <span class="number">3</span> <span class="number">12</span> LOAD_FAST <span class="number">0</span> (x)</span><br><span class="line"> <span class="number">15</span> STORE_FAST <span class="number">2</span> (temp)</span><br><span class="line"></span><br><span class="line"> <span class="number">4</span> <span class="number">18</span> LOAD_FAST <span class="number">1</span> (y)</span><br><span class="line"> <span class="number">21</span> STORE_FAST <span class="number">0</span> (x)</span><br><span class="line"></span><br><span class="line"> <span class="number">5</span> <span class="number">24</span> LOAD_FAST <span class="number">2</span> (temp)</span><br><span class="line"> <span class="number">27</span> STORE_FAST <span class="number">1</span> (y)</span><br><span class="line"> <span class="number">30</span> LOAD_CONST <span class="number">0</span> (None)</span><br><span class="line"> <span class="number">33</span> RETURN_VALUE</span><br></pre></td></tr></table></figure>
<p>通过字节码可以看出:swap1使用了ROT_TWO指令,而swap2比swap1多执行了一个LOAD_FAST+STORE_FAST(入栈和赋值)。</p>
<p>那么ROT_TWO做了什么事情,使得变量能够成功交换,且比LOAD_FAST+STORE_FAST效率高呢?</p>
<p>查看官方api,它的作用是交换栈顶的两个元素:<br><figure class="highlight livecodeserver"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ROT_TWO()</span><br><span class="line">Swaps <span class="keyword">the</span> <span class="literal">two</span> top-most stack <span class="keyword">items</span>.</span><br></pre></td></tr></table></figure></p>
<p>而ROT_TWO在cpython的实现如下:<br><figure class="highlight abnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">TARGET(ROT_TWO) {</span><br><span class="line"> PyObject *top = TOP()<span class="comment">;</span></span><br><span class="line"> PyObject *second = SECOND()<span class="comment">;</span></span><br><span class="line"> SET_TOP(second)<span class="comment">;</span></span><br><span class="line"> SET_SECOND(top)<span class="comment">;</span></span><br><span class="line"> FAST_DISPATCH()<span class="comment">;</span></span><br><span class="line"> }</span><br></pre></td></tr></table></figure></p>
<p>SET_TOP和SET_SECOND的定义:<br><figure class="highlight lisp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">#define SET_TOP(<span class="name">v</span>) (<span class="name">stack_pointer</span>[<span class="number">-1</span>] = (<span class="name">v</span>))</span><br><span class="line">#define SET_SECOND(<span class="name">v</span>) (<span class="name">stack_pointer</span>[<span class="number">-2</span>] = (<span class="name">v</span>))</span><br></pre></td></tr></table></figure></p>
<p>栈存放的是对象的指针,那么x,y=y,x所做的就是将栈顶的两个指针互换了一下,从而实现了x和y值的交换。而直接使用指针进行交换,就是其为什么执行速度会更快了。</p>
]]></content>
<summary type="html">
<![CDATA[<p>python数值交换不推荐使用中间值,使用Pythonic的实现不仅简洁,而且执行效率高。<br>]]>
</summary>
<category term="python" scheme="http://yoursite.com/tags/python/"/>
<category term="python" scheme="http://yoursite.com/categories/python/"/>
</entry>
<entry>
<title><![CDATA[Ubuntu配置连接android手机]]></title>
<link href="http://yoursite.com/2016/03/03/AdbUsb/"/>
<id>http://yoursite.com/2016/03/03/AdbUsb/</id>
<published>2016-03-03T15:06:43.000Z</published>
<updated>2016-03-05T04:08:33.000Z</updated>
<content type="html"><![CDATA[<p>在Ubuntu系统中,默认情况下一般用户是不能直接访问USB设备的。因此,为了能够让Ubuntu连接上android手机,我们需要做一定的配置。以下介绍几种配置的方法。<br><a id="more"></a></p>
<h2 id="方法一">方法一</h2><p>android官方网站建议我们采用以下方法配置列表内容</p>
<ul>
<li><p>新建规则文件</p>
<figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo touch <span class="regexp">/etc/u</span>dev<span class="regexp">/rules.d/</span><span class="number">51</span>-android.rules</span><br></pre></td></tr></table></figure>
</li>
<li><p>执行命令添加</p>
</li>
</ul>
<figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget -S -O - http:<span class="regexp">//</span>source.android.com<span class="regexp">/source/</span><span class="number">51</span>-android.rules | sed <span class="string">"s/<username>/$USER/"</span> | sudo tee ><span class="regexp">/dev/</span>null <span class="regexp">/etc/u</span>dev<span class="regexp">/rules.d/</span><span class="number">51</span>-android.rules; sudo udevadm control --reload-rules</span><br></pre></td></tr></table></figure>
<p>这种方式是android在其服务器中配置好了nexus系列手机的USB连接规则,然后通过命令获取并写入本地规则文件中。<br>但是有以下的缺点:只适合nexus系列手机,且断网情况下没法使用</p>
<h2 id="方法二">方法二</h2><p>单独配置每一台手机的USB规则</p>
<ul>
<li>查看当前插入的手机设备信息</li>
</ul>
<figure class="highlight vhdl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">lsusb -v | less</span><br><span class="line"><span class="keyword">Bus</span> <span class="number">001</span> Device <span class="number">027</span>: ID <span class="number">18</span>d1:<span class="number">4e30</span> Google Inc. </span><br><span class="line">Couldn<span class="symbol">'t</span> <span class="keyword">open</span> device, some information will be missing</span><br><span class="line">Device Descriptor:</span><br><span class="line">...</span><br><span class="line"> idVendor <span class="number">0</span>x046d Google Inc.</span><br><span class="line"> idProduct <span class="number">0</span>xc31c</span><br></pre></td></tr></table></figure>
<ul>
<li>配置规则</li>
</ul>
<figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo vi <span class="regexp">/etc/u</span>dev<span class="regexp">/rules.d/</span><span class="number">51</span>-android.rules</span><br></pre></td></tr></table></figure>
<p>加入以下内容<br><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># adb protocol on passion</span></span><br><span class="line"><span class="attribute">SUBSYSTEM</span>=="usb", ATTR{idVendor}==<span class="string">"046d"</span>, ATTR{idProduct}==<span class="string">"c31c"</span>, <span class="attribute">MODE</span>=<span class="string">"0600"</span>, <span class="attribute">OWNER</span>=<span class="string">"zhonghq"</span></span><br></pre></td></tr></table></figure></p>
<p>OWNER为当前登录用户</p>
<ul>
<li>重启usb服务</li>
</ul>
<figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo<span class="built_in"> service </span>udev restart</span><br></pre></td></tr></table></figure>
<p>这种方法也存在较大的缺点,只能配置一台手机,而且配置操作叫复杂。</p>
<h2 id="方法三">方法三</h2><p>通用配置,是根据方法二的优化版本</p>
<ul>
<li>配置规则</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo vi /etc/udev/rules.d/51-android.rules</span><br></pre></td></tr></table></figure>
<p>加入以下内容<br><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">SUBSYSTEM</span>==<span class="string">"usb"</span>, ENV{DEVTYPE}==<span class="string">"usb_device"</span>, MODE=<span class="string">"0666"</span></span><br></pre></td></tr></table></figure></p>
<ul>
<li>重启usb服务</li>
</ul>
<figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo<span class="built_in"> service </span>udev restart</span><br></pre></td></tr></table></figure>
<p>此方法配置起来方便快捷,无需查看手机的信息,而且能够适配大部分的手机。</p>
<h2 id="方法四">方法四</h2><p>方法三已经非常实用了,但是在使用过程中,我们还是会发现有部分手机不能连接上,下面这种方法可以作为方法三的辅助。</p>
<ul>
<li>查看当前插入的手机设备信息</li>
</ul>
<figure class="highlight vhdl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">lsusb -v | less</span><br><span class="line"><span class="keyword">Bus</span> <span class="number">001</span> Device <span class="number">027</span>: ID <span class="number">18</span>d1:<span class="number">4e30</span> Google Inc. </span><br><span class="line">Couldn<span class="symbol">'t</span> <span class="keyword">open</span> device, some information will be missing</span><br><span class="line">Device Descriptor:</span><br><span class="line">...</span><br><span class="line"> idVendor <span class="number">0</span>x046d Google Inc.</span><br><span class="line"> idProduct <span class="number">0</span>xc31c</span><br></pre></td></tr></table></figure>
<ul>
<li>配置规则</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi ~/.android/adb_usb.ini</span><br></pre></td></tr></table></figure>
<p>在文件中加入idVendor号<br><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">0x046d</span></span><br></pre></td></tr></table></figure></p>
<ul>
<li>重启adb服务</li>
</ul>
<pre><code class="shell">adb stop-server adb start-server
</code></pre>
<p>参考文档:<a href="http://source.android.com/source/initializing.html" target="_blank" rel="noopener">Establishing a Build Environment</a></p>
]]></content>
<summary type="html">
<![CDATA[<p>在Ubuntu系统中,默认情况下一般用户是不能直接访问USB设备的。因此,为了能够让Ubuntu连接上android手机,我们需要做一定的配置。以下介绍几种配置的方法。<br>]]>
</summary>
<category term="Ubuntu" scheme="http://yoursite.com/tags/Ubuntu/"/>
<category term="android" scheme="http://yoursite.com/tags/android/"/>
<category term="连接" scheme="http://yoursite.com/tags/%E8%BF%9E%E6%8E%A5/"/>
<category term="linux" scheme="http://yoursite.com/categories/linux/"/>
</entry>
<entry>
<title><![CDATA[linux如何编译和安装infer]]></title>
<link href="http://yoursite.com/2016/02/24/InferCompile/"/>
<id>http://yoursite.com/2016/02/24/InferCompile/</id>
<published>2016-02-24T14:45:05.000Z</published>
<updated>2016-02-25T12:57:18.000Z</updated>
<content type="html"><![CDATA[<p>facebook推出infer静态代码检测工具编译和安装是相对复杂的一个操作,官方文档是英文的,安装顺序也有点乱,而且部分依赖插件也没有给出安装步骤,如果安装的时候不注意很容易导致问题。因此,将我在Linux上的安装过程分享出来,作为一份中文参考文档。<br><a id="more"></a></p>
<h2 id="依赖插件">依赖插件</h2><p>插件是编译infer的先决条件,linux下需要依赖的插件如下:</p>
<ul>
<li>opam >= 1.2.0</li>
<li>Python 2.7</li>
<li>Java (only needed for the Java analysis)</li>
<li>gcc >= 4.7.2 or clang >= 3.1 (only needed for the C/Objective-C analysis)</li>
<li>autoconf >= 2.63 and automake >= 1.11.1 (if building from git)</li>
</ul>
<h2 id="安装插件">安装插件</h2><p>针对我使用的Ubuntu系统,根据不同的系统版本执行下述命令:</p>
<h3 id="Ubuntu_14-04_LTS">Ubuntu 14.04 LTS</h3><pre><code class="shell">sudo apt-get update sudo apt-get upgrade sudo apt-get install -y \ autoconf \ automake \ build-essential \ git \ libgmp-dev \ libmpc-dev \ libmpfr-dev \ m4 \ openjdk-7-jdk \ python-software-properties \ unzip \ zlib1g-dev
</code></pre>
<h3 id="Ubuntu_12-04-4_LTS">Ubuntu 12.04.4 LTS</h3><pre><code class="shell">sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get upgrade sudo apt-get install -y \ autoconf \ automake \ build-essential \ g++-4.8 \ gcc-4.8 \ git \ libgmp-dev \ libmpc-dev \ libmpfr-dev \ m4 \ openjdk-7-jdk \ python-software-properties \ unzip \ zlib1g-dev sudo update-alternatives \ --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 60 \ --slave /usr/bin/g++ g++ /usr/bin/g++-4.8
</code></pre>
<h3 id="设置opam">设置opam</h3><p>据官网所言,opam在Linux的部分发行版本中是缺失的,所以需要自己下载安装:</p>
<pre><code class="shell">wget https://github.com/ocaml/opam/releases/download/1.2.2/opam-1.2.2-x86_64-Linux chmod +x opam-1.2.2-x86_64-Linux sudo cp opam-1.2.2-x86_64-Linux /usr/local/bin/opam opam init --comp=4.02.3 eval `opam config env`
</code></pre>
<h2 id="安装编译">安装编译</h2><p>执行以下命令安装编译:</p>
<pre><code class="shell"># Checkout Infer git clone https://github.com/facebook/infer.git cd infer ./autogen.sh ./configure make # or make java # Install Infer into your PATH export PATH=`pwd`/infer/bin:$PATH
</code></pre>
<p>编译完成后,就可以进行代码的静态扫描了,具体使用方式可查考<a href="http://fbinfer.com/docs/hello-world.html" target="_blank" rel="noopener">infer使用教程</a>。</p>
<p>如果根据以上方法编译安装后还有问题,可参考<a href="http://hqzhon.cc/2016/01/26/infer/" target="_blank" rel="noopener">infer静态代码扫描不能执行问题定位</a>。</p>
<p>参考文档:<a href="https://github.com/facebook/infer/blob/master/INSTALL.md#install-the-dependencies" target="_blank" rel="noopener">How to compile and install Infer</a></p>
]]></content>
<summary type="html">
<![CDATA[<p>facebook推出infer静态代码检测工具编译和安装是相对复杂的一个操作,官方文档是英文的,安装顺序也有点乱,而且部分依赖插件也没有给出安装步骤,如果安装的时候不注意很容易导致问题。因此,将我在Linux上的安装过程分享出来,作为一份中文参考文档。<br>]]>
</summary>
<category term="linux" scheme="http://yoursite.com/tags/linux/"/>
<category term="infer" scheme="http://yoursite.com/tags/infer/"/>
<category term="facebook" scheme="http://yoursite.com/tags/facebook/"/>
<category term="静态代码扫描" scheme="http://yoursite.com/tags/%E9%9D%99%E6%80%81%E4%BB%A3%E7%A0%81%E6%89%AB%E6%8F%8F/"/>
<category term="linux" scheme="http://yoursite.com/categories/linux/"/>
</entry>
<entry>
<title><![CDATA[unbuntu安装和使用appium遇到的问题解决方案]]></title>
<link href="http://yoursite.com/2016/02/22/Appium/"/>
<id>http://yoursite.com/2016/02/22/Appium/</id>
<published>2016-02-22T13:56:11.000Z</published>
<updated>2016-02-22T14:56:01.000Z</updated>
<content type="html"><![CDATA[<p>近期发现一款appium小工具,看着功能不错,就在自己的unbuntu机器搭建了一个appium的环境,其中遇到好几个问题,这里将遇到的问题及解决方案分享出来。<br><a id="more"></a></p>
<h2 id="安装后无法使用">安装后无法使用</h2><h3 id="问题">问题</h3><pre><code>Appium will <span class="keyword">not</span> work <span class="keyword">if</span> used <span class="keyword">or</span> installed <span class="keyword">with</span> sudo
error: Appium will <span class="keyword">not</span> work <span class="keyword">if</span> used <span class="keyword">or</span> installed <span class="keyword">with</span> sudo. Please rerun/install <span class="keyword">as</span> a non-root user. <span class="keyword">If</span> you had <span class="keyword">to</span> install Appium <span class="keyword">using</span> `sudo npm install -g appium`, the solution <span class="keyword">is</span> <span class="keyword">to</span> reinstall Node <span class="keyword">using</span> a <span class="function"><span class="keyword">method</span> <span class="params">(Homebrew, <span class="keyword">for</span> example)</span> <span class="title">that</span> <span class="title">doesn</span>'<span class="title">t</span> <span class="title">require</span> <span class="title">sudo</span> <span class="title">to</span> <span class="title">install</span> <span class="title">global</span> <span class="title">npm</span> <span class="title">packages</span>.
[1]+ <span class="title">Exit</span> 1 <span class="title">appium</span></span>
</code></pre><p>该问题显示appium不能使用root用户来安装,不然无法运行,所以需要卸载用root用户安装的appium,该用一般用户来安装。</p>
<h3 id="解决方案">解决方案</h3><ul>
<li><p>改变node的所有者</p>
<pre><code class="shell">cd /usr/local/lib sudo chown -R bixiaopeng node_modules
</code></pre>
</li>
<li><p>问题1: 卸载appium</p>
<pre><code class="shell">npm uninstall appium -g
</code></pre>
</li>
<li>重新安装appium<pre><code class="shell">npm install -g appium
</code></pre>
</li>
<li>启动<pre><code class="shell">appium &
</code></pre>
</li>
</ul>
<h2 id="问题2:_一般用户安装问题">问题2: 一般用户安装问题</h2><h3 id="问题-1">问题</h3><p>非root用户在执行npm install -g appium安装时可能会遇到以下问题</p>
<pre><code>> ws@<span class="number">0.4</span><span class="number">.31</span> install <span class="regexp">/lib/</span>node_modules<span class="regexp">/appium/</span>node_modules/ws
> (node-gyp rebuild <span class="number">2</span>> builderror.log) || (exit <span class="number">0</span>)
CXX(target) Release<span class="regexp">/obj.target/</span>bufferutil<span class="regexp">/src/</span>bufferutil.o
SOLINK_MODULE(target) Release/bufferutil.node
SOLINK_MODULE(target) Release/bufferutil.<span class="string">node:</span> Finished
CXX(target) Release<span class="regexp">/obj.target/</span>validation<span class="regexp">/src/</span>validation.o
SOLINK_MODULE(target) Release/validation.node
SOLINK_MODULE(target) Release/validation.<span class="string">node:</span> Finished
npm WARN engine hawk@<span class="number">0.10</span><span class="number">.2</span>: <span class="string">wanted:</span> {<span class="string">"node"</span>:<span class="string">"0.8.x"</span>} (<span class="string">current:</span> {<span class="string">"node"</span>:<span class="string">"v0.10.28"</span>,<span class="string">"npm"</span>:<span class="string">"1.4.15"</span>})
npm WARN engine cryptiles@<span class="number">0.1</span><span class="number">.3</span>: <span class="string">wanted:</span> {<span class="string">"node"</span>:<span class="string">"0.8.x"</span>} (<span class="string">current:</span> {<span class="string">"node"</span>:<span class="string">"v0.10.28"</span>,<span class="string">"npm"</span>:<span class="string">"1.4.15"</span>})
npm WARN engine sntp@<span class="number">0.1</span><span class="number">.4</span>: <span class="string">wanted:</span> {<span class="string">"node"</span>:<span class="string">"0.8.x"</span>} (<span class="string">current:</span> {<span class="string">"node"</span>:<span class="string">"v0.10.28"</span>,<span class="string">"npm"</span>:<span class="string">"1.4.15"</span>})
npm WARN engine hoek@<span class="number">0.7</span><span class="number">.6</span>: <span class="string">wanted:</span> {<span class="string">"node"</span>:<span class="string">"0.8.x"</span>} (<span class="string">current:</span> {<span class="string">"node"</span>:<span class="string">"v0.10.28"</span>,<span class="string">"npm"</span>:<span class="string">"1.4.15"</span>})
npm WARN engine boom@<span class="number">0.3</span><span class="number">.8</span>: <span class="string">wanted:</span> {<span class="string">"node"</span>:<span class="string">"0.8.x"</span>} (<span class="string">current:</span> {<span class="string">"node"</span>:<span class="string">"v0.10.28"</span>,<span class="string">"npm"</span>:<span class="string">"1.4.15"</span>})
npm ERR! <span class="string">Error:</span> EACCES, symlink <span class="string">'/lib/node_modules/appium/bin/appium.js'</span>
npm ERR! { [<span class="string">Error:</span> EACCES, symlink <span class="string">'/lib/node_modules/appium/bin/appium.js'</span>]
npm ERR! <span class="string">errno:</span> <span class="number">3</span>,
npm ERR! <span class="string">code:</span> <span class="string">'EACCES'</span>,
npm ERR! <span class="string">path:</span> <span class="string">'/lib/node_modules/appium/bin/appium.js'</span> }
npm ERR!
npm ERR! Please <span class="keyword">try</span> running <span class="keyword">this</span> command again <span class="keyword">as</span> root/Administrator.
npm ERR! System Darwin <span class="number">13.2</span><span class="number">.0</span>
npm ERR! command <span class="string">"node"</span> <span class="string">"/usr/local/bin/npm"</span> <span class="string">"install"</span> <span class="string">"-g"</span> <span class="string">"appium"</span>
npm ERR! cwd <span class="regexp">/Users/</span>stefanow<span class="regexp">/Code/</span>jqueryuk-workshop-<span class="number">2014</span>
npm ERR! node -v v0<span class="number">.10</span><span class="number">.28</span>
npm ERR! npm -v <span class="number">1.4</span><span class="number">.15</span>
npm ERR! path <span class="regexp">/lib/</span>node_modules<span class="regexp">/appium/</span>bin/appium.js
npm ERR! code EACCES
npm ERR! errno <span class="number">3</span>
npm ERR! stack <span class="string">Error:</span> EACCES, symlink <span class="string">'/lib/node_modules/appium/bin/appium.js'</span>
npm ERR!
npm ERR! Additional logging details can be found <span class="string">in:</span>
npm ERR! <span class="regexp">/Users/</span>stefanow<span class="regexp">/Code/</span>jqueryuk-workshop-<span class="number">2014</span>/npm-debug.log
npm ERR! not ok code <span class="number">0</span>
</code></pre><p>该问题显示没发访问部分文件,请使用root用户重试,很显然是权限不够,但是,问题1已经说过不能使用root用户进行安装。那么关键问题就是怎么解决权限问题了,首先我们想到的是修改目录的权限,执行以下命令:</p>
<pre><code class="shell">sudo chmod 777 /lib/node_modules -R
</code></pre>
<p>但是,重新执行发现问题依旧。<br>查看/lib/node_modules目录,我们发现并没有/lib/node_modules/appium/bin/appium.js文件。显然,该文件是安装时生成的,因此问题应该出在安装起npm上,查看npm相关文档我们发现日志中提到的符号链接的路径是可以修改的,因此,解决权限问题可以将该符号链接修改到用户有权限的目录中。</p>
<h3 id="解决方案-1">解决方案</h3><ul>
<li>执行以下命令修改符号链接路径<pre><code class="shell">npm config set prefix '~/.npm-packages'
</code></pre>
</li>
<li>将新路径添加到环境变量<pre><code class="shell">vim .bashrc # home目录下执行 source .bashrc export PATH="$PATH:$HOME/.npm-packages/bin"
</code></pre>
</li>
</ul>
<h2 id="问题3:_appium启动问题">问题3: appium启动问题</h2><h3 id="问题-2">问题</h3><p>appium启动时可能会遇到下列问题</p>
<pre><code>zhonghq@zhonghq:~$ appium
error: uncaughtException: fn must be a function
<span class="type">See</span> http://goo.gl/<span class="number">916</span>lJJ
date=<span class="type">Sat</span> <span class="type">Nov</span> <span class="number">21</span> <span class="number">2015</span> <span class="number">10</span>:<span class="number">37</span>:<span class="number">25</span> <span class="type">GMT</span>+<span class="number">0800</span> (<span class="type">HKT</span>), pid=<span class="number">2504</span>, uid=<span class="number">501</span>, gid=<span class="number">20</span>, cwd=/usr/local/lib/node_modules/appium, execPath=/usr/local/bin/node, version=v0.<span class="number">10</span>.<span class="number">34</span>, argv=[node, /usr/local/bin/appium], rss=<span class="number">103559168</span>, heapTotal=<span class="number">86062080</span>, heapUsed=<span class="number">56309664</span>, loadavg=[<span class="number">1</span>.<span class="number">6328125</span>, <span class="number">1</span>.<span class="number">86767578125</span>, <span class="number">1</span>.<span class="number">81103515625</span>], uptime=<span class="number">39552</span>, trace=[column=<span class="number">15</span>, file=/usr/local/lib/node_modules/appium/node_modules/appium-chromedriver/node_modules/appium-jsonwp-proxy/node_modules/appium-support/node_modules/bluebird/js/main/promisify.js, function=<span class="type">Function</span>.<span class="type">Promise</span>.promisify, line=<span class="number">268</span>, <span class="keyword">method</span>=<span class="type">Promise</span>.promisify, native=<span class="literal">false</span>, column=<span class="number">13</span>, file=lib/fs.js, function=, line=<span class="number">46</span>, <span class="keyword">method</span>=null, native=<span class="literal">false</span>, column=<span class="number">26</span>, file=module.js, function=<span class="type">Module</span>._compile, line=<span class="number">456</span>, <span class="keyword">method</span>=_compile, native=<span class="literal">false</span>, column=<span class="number">10</span>, file=module.js, function=<span class="type">Object</span>.<span class="type">Module</span>._extensions..js, line=<span class="number">474</span>, <span class="keyword">method</span>=<span class="type">Module</span>._extensions..js, native=<span class="literal">false</span>, column=<span class="number">32</span>, file=module.js, function=<span class="type">Module</span>.load, line=<span class="number">356</span>, <span class="keyword">method</span>=load, native=<span class="literal">false</span>, column=<span class="number">12</span>, file=module.js, function=<span class="type">Function</span>.<span class="type">Module</span>._load, line=<span class="number">312</span>, <span class="keyword">method</span>=<span class="type">Module</span>._load, native=<span class="literal">false</span>, column=<span class="number">17</span>, file=module.js, function=<span class="type">Module</span>.require, line=<span class="number">364</span>, <span class="keyword">method</span>=require, native=<span class="literal">false</span>, column=<span class="number">17</span>, file=module.js, function=require, line=<span class="number">380</span>, <span class="keyword">method</span>=null, native=<span class="literal">false</span>, column=<span class="number">11</span>, file=/usr/local/lib/node_modules/appium/node_modules/appium-chromedriver/node_modules/appium-jsonwp-proxy/node_modules/appium-support/build/lib/tempdir.js, function=, line=<span class="number">12</span>, <span class="keyword">method</span>=null, native=<span class="literal">false</span>, column=<span class="number">26</span>, file=module.js, function=<span class="type">Module</span>._compile, line=<span class="number">456</span>, <span class="keyword">method</span>=_compile, native=<span class="literal">false</span>, column=<span class="number">10</span>, file=module.js, function=<span class="type">Object</span>.<span class="type">Module</span>._extensions..js, line=<span class="number">474</span>, <span class="keyword">method</span>=<span class="type">Module</span>._extensions..js, native=<span class="literal">false</span>, column=<span class="number">32</span>, file=module.js, function=<span class="type">Module</span>.load, line=<span class="number">356</span>, <span class="keyword">method</span>=load, native=<span class="literal">false</span>, column=<span class="number">12</span>, file=module.js, function=<span class="type">Function</span>.<span class="type">Module</span>._load, line=<span class="number">312</span>, <span class="keyword">method</span>=<span class="type">Module</span>._load, native=<span class="literal">false</span>, column=<span class="number">17</span>, file=module.js, function=<span class="type">Module</span>.require, line=<span class="number">364</span>, <span class="keyword">method</span>=require, native=<span class="literal">false</span>, column=<span class="number">17</span>, file=module.js, function=require, line=<span class="number">380</span>, <span class="keyword">method</span>=null, native=<span class="literal">false</span>, column=<span class="number">19</span>, file=/usr/local/lib/node_modules/appium/node_modules/appium-chromedriver/node_modules/appium-jsonwp-proxy/node_modules/appium-support/build/index.js, function=, line=<span class="number">11</span>, <span class="keyword">method</span>=null, native=<span class="literal">false</span>, column=<span class="number">26</span>, file=module.js, function=<span class="type">Module</span>._compile, line=<span class="number">456</span>, <span class="keyword">method</span>=_compile, native=<span class="literal">false</span>, column=<span class="number">10</span>, file=module.js, function=<span class="type">Object</span>.<span class="type">Module</span>._extensions..js, line=<span class="number">474</span>, <span class="keyword">method</span>=<span class="type">Module</span>._extensions..js, native=<span class="literal">false</span>, column=<span class="number">32</span>, file=module.js, function=<span class="type">Module</span>.load, line=<span class="number">356</span>, <span class="keyword">method</span>=load, native=<span class="literal">false</span>, column=<span class="number">12</span>, file=module.js, function=<span class="type">Function</span>.<span class="type">Module</span>._load, line=<span class="number">312</span>, <span class="keyword">method</span>=<span class="type">Module</span>._load, native=<span class="literal">false</span>, column=<span class="number">17</span>, file=module.js, function=<span class="type">Module</span>.require, line=<span class="number">364</span>, <span class="keyword">method</span>=require, native=<span class="literal">false</span>, column=<span class="number">17</span>, file=module.js, function=require, line=<span class="number">380</span>, <span class="keyword">method</span>=null, native=<span class="literal">false</span>, column=<span class="number">42</span>, file=lib/proxy.js, function=, line=<span class="number">2</span>, <span class="keyword">method</span>=null, native=<span class="literal">false</span>, column=<span class="number">26</span>, file=module.js, function=<span class="type">Module</span>._compile, line=<span class="number">456</span>, <span class="keyword">method</span>=_compile, native=<span class="literal">false</span>, column=<span class="number">10</span>, file=module.js, function=<span class="type">Object</span>.<span class="type">Module</span>._extensions..js, line=<span class="number">474</span>, <span class="keyword">method</span>=<span class="type">Module</span>._extensions..js, native=<span class="literal">false</span>, column=<span class="number">32</span>, file=module.js, function=<span class="type">Module</span>.load, line=<span class="number">356</span>, <span class="keyword">method</span>=load, native=<span class="literal">false</span>, column=<span class="number">12</span>, file=module.js, function=<span class="type">Function</span>.<span class="type">Module</span>._load, line=<span class="number">312</span>, <span class="keyword">method</span>=<span class="type">Module</span>._load, native=<span class="literal">false</span>, column=<span class="number">17</span>, file=module.js, function=<span class="type">Module</span>.require, line=<span class="number">364</span>, <span class="keyword">method</span>=require, native=<span class="literal">false</span>, column=<span class="number">17</span>, file=module.js, function=require, line=<span class="number">380</span>, <span class="keyword">method</span>=null, native=<span class="literal">false</span>, column=<span class="number">17</span>, file=/usr/local/lib/node_modules/appium/node_modules/appium-chromedriver/node_modules/appium-jsonwp-proxy/build/index.js, function=, line=<span class="number">9</span>, <span class="keyword">method</span>=null, native=<span class="literal">false</span>, column=<span class="number">26</span>, file=module.js, function=<span class="type">Module</span>._compile, line=<span class="number">456</span>, <span class="keyword">method</span>=_compile, native=<span class="literal">false</span>, column=<span class="number">10</span>, file=module.js, function=<span class="type">Object</span>.<span class="type">Module</span>._extensions..js, line=<span class="number">474</span>, <span class="keyword">method</span>=<span class="type">Module</span>._extensions..js, native=<span class="literal">false</span>, column=<span class="number">32</span>, file=module.js, function=<span class="type">Module</span>.load, line=<span class="number">356</span>, <span class="keyword">method</span>=load, native=<span class="literal">false</span>, column=<span class="number">12</span>, file=module.js, function=<span class="type">Function</span>.<span class="type">Module</span>._load, line=<span class="number">312</span>, <span class="keyword">method</span>=<span class="type">Module</span>._load, native=<span class="literal">false</span>, column=<span class="number">17</span>, file=module.js, function=<span class="type">Module</span>.require, line=<span class="number">364</span>, <span class="keyword">method</span>=require, native=<span class="literal">false</span>, column=<span class="number">17</span>, file=module.js, function=require, line=<span class="number">380</span>, <span class="keyword">method</span>=null, native=<span class="literal">false</span>, column=<span class="number">28</span>, file=lib/chromedriver.js, function=, line=<span class="number">3</span>, <span class="keyword">method</span>=null, native=<span class="literal">false</span>, column=<span class="number">26</span>, file=module.js, function=<span class="type">Module</span>._compile, line=<span class="number">456</span>, <span class="keyword">method</span>=_compile, native=<span class="literal">false</span>, column=<span class="number">10</span>, file=module.js, function=<span class="type">Object</span>.<span class="type">Module</span>._extensions..js, line=<span class="number">474</span>, <span class="keyword">method</span>=<span class="type">Module</span>._extensions..js, native=<span class="literal">false</span>, column=<span class="number">32</span>, file=module.js, function=<span class="type">Module</span>.load, line=<span class="number">356</span>, <span class="keyword">method</span>=load, native=<span class="literal">false</span>], stack=[<span class="type">TypeError</span>: fn must be a function, , <span class="type">See</span> http://goo.gl/<span class="number">916</span>lJJ, , at <span class="type">Function</span>.<span class="type">Promise</span>.promisify (/usr/local/lib/node_modules/appium/node_modules/appium-chromedriver/node_modules/appium-jsonwp-proxy/node_modules/appium-support/node_modules/bluebird/js/main/promisify.js:<span class="number">268</span>:<span class="number">15</span>), at <span class="type">Object</span>.<anonymous> (lib/fs.js:<span class="number">46</span>:<span class="number">13</span>), at <span class="type">Module</span>._compile (module.js:<span class="number">456</span>:<span class="number">26</span>), at <span class="type">Object</span>.<span class="type">Module</span>._extensions..js (module.js:<span class="number">474</span>:<span class="number">10</span>), at <span class="type">Module</span>.load (module.js:<span class="number">356</span>:<span class="number">32</span>), at <span class="type">Function</span>.<span class="type">Module</span>._load (module.js:<span class="number">312</span>:<span class="number">12</span>), at <span class="type">Module</span>.require (module.js:<span class="number">364</span>:<span class="number">17</span>), at require (module.js:<span class="number">380</span>:<span class="number">17</span>), at <span class="type">Object</span>.<anonymous> (/usr/local/lib/node_modules/appium/node_modules/appium-chromedriver/node_modules/appium-jsonwp-proxy/node_modules/appium-support/build/lib/tempdir.js:<span class="number">12</span>:<span class="number">11</span>), at <span class="type">Module</span>._compile (module.js:<span class="number">456</span>:<span class="number">26</span>), at <span class="type">Object</span>.<span class="type">Module</span>._extensions..js (module.js:<span class="number">474</span>:<span class="number">10</span>), at <span class="type">Module</span>.load (module.js:<span class="number">356</span>:<span class="number">32</span>), at <span class="type">Function</span>.<span class="type">Module</span>._load (module.js:<span class="number">312</span>:<span class="number">12</span>), at <span class="type">Module</span>.require (module.js:<span class="number">364</span>:<span class="number">17</span>), at require (module.js:<span class="number">380</span>:<span class="number">17</span>), at <span class="type">Object</span>.<anonymous> (/usr/local/lib/node_modules/appium/node_modules/appium-chromedriver/node_modules/appium-jsonwp-proxy/node_modules/appium-support/build/index.js:<span class="number">11</span>:<span class="number">19</span>), at <span class="type">Module</span>._compile (module.js:<span class="number">456</span>:<span class="number">26</span>), at <span class="type">Object</span>.<span class="type">Module</span>._extensions..js (module.js:<span class="number">474</span>:<span class="number">10</span>), at <span class="type">Module</span>.load (module.js:<span class="number">356</span>:<span class="number">32</span>), at <span class="type">Function</span>.<span class="type">Module</span>._load (module.js:<span class="number">312</span>:<span class="number">12</span>), at <span class="type">Module</span>.require (module.js:<span class="number">364</span>:<span class="number">17</span>), at require (module.js:<span class="number">380</span>:<span class="number">17</span>), at <span class="type">Object</span>.<anonymous> (lib/proxy.js:<span class="number">2</span>:<span class="number">42</span>), at <span class="type">Module</span>._compile (module.js:<span class="number">456</span>:<span class="number">26</span>), at <span class="type">Object</span>.<span class="type">Module</span>._extensions..js (module.js:<span class="number">474</span>:<span class="number">10</span>), at <span class="type">Module</span>.load (module.js:<span class="number">356</span>:<span class="number">32</span>), at <span class="type">Function</span>.<span class="type">Module</span>._load (module.js:<span class="number">312</span>:<span class="number">12</span>), at <span class="type">Module</span>.require (module.js:<span class="number">364</span>:<span class="number">17</span>), at require (module.js:<span class="number">380</span>:<span class="number">17</span>), at <span class="type">Object</span>.<anonymous> (/usr/local/lib/node_modules/appium/node_modules/appium-chromedriver/node_modules/appium-jsonwp-proxy/build/index.js:<span class="number">9</span>:<span class="number">17</span>), at <span class="type">Module</span>._compile (module.js:<span class="number">456</span>:<span class="number">26</span>), at <span class="type">Object</span>.<span class="type">Module</span>._extensions..js (module.js:<span class="number">474</span>:<span class="number">10</span>), at <span class="type">Module</span>.load (module.js:<span class="number">356</span>:<span class="number">32</span>), at <span class="type">Function</span>.<span class="type">Module</span>._load (module.js:<span class="number">312</span>:<span class="number">12</span>), at <span class="type">Module</span>.require (module.js:<span class="number">364</span>:<span class="number">17</span>), at require (module.js:<span class="number">380</span>:<span class="number">17</span>), at <span class="type">Object</span>.<anonymous> (lib/chromedriver.js:<span class="number">3</span>:<span class="number">28</span>), at <span class="type">Module</span>._compile (module.js:<span class="number">456</span>:<span class="number">26</span>), at <span class="type">Object</span>.<span class="type">Module</span>._extensions..js (module.js:<span class="number">474</span>:<span class="number">10</span>), at <span class="type">Module</span>.load (module.js:<span class="number">356</span>:<span class="number">32</span>)]
</code></pre><p>google我们发现问题是node.js版本太低导致。<br>首先我们想到的解决方案是直接使用以下命令</p>
<pre><code class="shell">sudo apt-get update sudo apt-get install nodejs
</code></pre>
<p>很可惜这种方式在unbuntu 14.04默认安装的nodejs版本还是v0.10.34,不支持我们安装的appium(版本1.4.16),那只能采用源码升级方式了。(注:查看nodejs版本号方法node -v,查看appium版本方法appium -v)</p>
<h3 id="解决方案-2">解决方案</h3><p>源码升级notejs</p>
<pre><code class="shell"># Using Ubuntu curl -sL https://deb.nodesource.com/setup_0.12 | sudo -E bash - sudo apt-get install -y nodejs
</code></pre>
<p>将nodejs版本升级到v0.12之后,appium就可以正常执行了。<br>至此大功告成!>_<</p>
]]></content>
<summary type="html">
<![CDATA[<p>近期发现一款appium小工具,看着功能不错,就在自己的unbuntu机器搭建了一个appium的环境,其中遇到好几个问题,这里将遇到的问题及解决方案分享出来。<br>]]>
</summary>
<category term="appium" scheme="http://yoursite.com/tags/appium/"/>
<category term="linux" scheme="http://yoursite.com/tags/linux/"/>
<category term="unbuntu" scheme="http://yoursite.com/tags/unbuntu/"/>
<category term="linux" scheme="http://yoursite.com/categories/linux/"/>
</entry>
<entry>
<title><![CDATA[infer静态代码扫描不能执行问题定位]]></title>
<link href="http://yoursite.com/2016/01/26/Infer/"/>
<id>http://yoursite.com/2016/01/26/Infer/</id>
<published>2016-01-26T04:55:10.000Z</published>
<updated>2016-01-26T05:09:49.000Z</updated>
<content type="html"><![CDATA[<h2 id="什么是infer">什么是infer</h2><p>facebook推出的静态代码检测工具,可以检测android和IOS应用的内存泄露和空指针问题。<br><a id="more"></a></p>
<h2 id="官方文档">官方文档</h2><ul>
<li><a href="http://fbinfer.com/" target="_blank" rel="noopener">infer官方介绍</a></li>
<li><a href="https://github.com/facebook/infer/blob/master/INSTALL.md#install-the-dependencies" target="_blank" rel="noopener">infer编译和安装方法</a></li>
</ul>
<h2 id="本文解决问题">本文解决问题</h2><p>使用源码安装的整个过程没有报错,在执行的时候会出现这个错误:<br><strong>Failed to run InferAnalyze binary, exiting</strong></p>
<h2 id="解决过程">解决过程</h2><p>Google解决方案大部分反馈结果如下:</p>
<p>About the “Failed to run InferAnalyze binary, exiting” error, you have to compile the binaries of Infer first, please follow the instructions <a href="http://fbinfer.com/docs/getting-started.html" target="_blank" rel="noopener">here</a>.</p>
<p>上面的结果让我们先编译infer二进制源码,很奇怪,我们其实进行源码安装的时候<strong>已经编译过了,而且没有报错</strong>。<br>按照上面的方式重新执行错误结果一致。</p>
<p>回头想想,为什么大部分结果会让我们回去编译?<br>重新翻看Facebook给出的<a href="https://github.com/facebook/infer/blob/master/INSTALL.md#install-the-dependencies" target="_blank" rel="noopener">infer编译和安装方法</a>,我们发现大部分该执行的命令都已经执行过了,但是有个比较陌生的插件opam,<strong>它是单独安装的</strong>。<br>会不会是它有什么依赖呢?<br>顺着这个思路很自然在<a href="https://github.com/facebook/infer/blob/master/INSTALL.md#install-the-dependencies" target="_blank" rel="noopener">infer编译和安装方法</a>中找到了下面这段话<br><strong>Install Infer from source without opam</strong><br>If for some reason you prefer to install Infer’s OCaml dependencies by some means other than opam, you can still compile Infer by running:<br><figure class="highlight n1ql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">./autogen.sh</span><br><span class="line">./configure</span><br><span class="line">make # or make java</span><br><span class="line"># Install <span class="keyword">Infer</span> <span class="keyword">into</span> your <span class="keyword">PATH</span></span><br><span class="line">export <span class="keyword">PATH</span>=<span class="symbol">`pwd`</span>/<span class="keyword">infer</span>/bin:$<span class="keyword">PATH</span></span><br></pre></td></tr></table></figure></p>
<p>执行上述脚本,注意执行./configure程序报错了,但是结果有很明显的提示让你执行:</p>
<pre><code class="shell">opam pin add --yes --no-action . opam install --deps-only infer
</code></pre>
<p>顺着提示继续执行,发现执行opam install –deps-only infer命令的时候又出错了,但是它依然很人性化的提示你执行下列脚本:</p>
<pre><code class="shell">opam depext camlp4.4.01+system
</code></pre>
<p>执行上述脚本后,将之前执行失败的脚本重新执行,不再出现报错了。<br>最后make编译会执行很长时间,等编译完成后就可以顺利执行infer静态检测内存泄露和空指针异常了。</p>
<p><strong>注:</strong>在我的unbuntu机器上直接make会报错,因为我只关注Android项目,所以执行的是make java,这样一切正常,现在正在跑项目中。暂时未研究是什么原因导致的,有兴趣的可以一起去研究讨论。</p>
]]></content>
<summary type="html">
<![CDATA[<h2 id="什么是infer">什么是infer</h2><p>facebook推出的静态代码检测工具,可以检测android和IOS应用的内存泄露和空指针问题。<br>]]>
</summary>
<category term="infer" scheme="http://yoursite.com/tags/infer/"/>
<category term="facebook" scheme="http://yoursite.com/tags/facebook/"/>
<category term="静态代码扫描" scheme="http://yoursite.com/tags/%E9%9D%99%E6%80%81%E4%BB%A3%E7%A0%81%E6%89%AB%E6%8F%8F/"/>
<category term="java" scheme="http://yoursite.com/tags/java/"/>
<category term="java" scheme="http://yoursite.com/categories/java/"/>
</entry>
<entry>
<title><![CDATA[javamail使用IMAP协议收取gmail邮件]]></title>
<link href="http://yoursite.com/2015/12/28/StoreMails/"/>
<id>http://yoursite.com/2015/12/28/StoreMails/</id>
<published>2015-12-28T13:46:15.000Z</published>
<updated>2015-12-30T15:08:41.000Z</updated>
<content type="html"><![CDATA[<p>年底了,绩效是逃不开的话题,为总结这一年来的工作情况,查看邮件是非常必要的。但是,邮件太多,如何筛选和保留成为一个问题,因此想到实现个自动统计邮件内容的工具,今天分享使用IMAP协议收取gmail邮件的实现方式。<br><a id="more"></a></p>
<h2 id="准备环境">准备环境</h2><p>新建一个java项目,并从oracle官网下载javamail.jar文件,导入到项目中。</p>
<h2 id="定义SMTP连接详情">定义SMTP连接详情</h2><p>首先,我们需要定义连接服务器相关的配置详情,如端口/主机名等。<br>在项目根目录下创建smtp.properties文件,并输入以下内容。<br><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">mail<span class="selector-class">.smtp</span><span class="selector-class">.host</span>=smtp<span class="selector-class">.gmail</span><span class="selector-class">.com</span></span><br><span class="line">mail<span class="selector-class">.smtp</span><span class="selector-class">.socketFactory</span><span class="selector-class">.port</span>=<span class="number">465</span></span><br><span class="line">mail<span class="selector-class">.smtp</span><span class="selector-class">.socketFactory</span><span class="selector-class">.class</span>=javax<span class="selector-class">.net</span><span class="selector-class">.ssl</span><span class="selector-class">.SSLSocketFactory</span></span><br><span class="line">mail<span class="selector-class">.smtp</span><span class="selector-class">.auth</span>=true</span><br><span class="line">mail<span class="selector-class">.smtp</span><span class="selector-class">.port</span>=<span class="number">465</span></span><br></pre></td></tr></table></figure></p>
<h2 id="加载配置信息">加载配置信息</h2><p>定义配置信息后,我们需要使用方法加载这些信息,并创建一个邮件会话。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">props.load(<span class="keyword">new</span> FileInputStream(<span class="keyword">new</span> File(<span class="string">"smtp.properties"</span>)));</span><br><span class="line">Session session = Session.getDefaultInstance(props, <span class="keyword">null</span>);</span><br></pre></td></tr></table></figure></p>
<h2 id="连接">连接</h2><p>创建一个store(javax.mail.Store)连接邮件服务器。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Store store = session.getStore(<span class="string">"imaps"</span>);</span><br><span class="line">store.connect(<span class="string">"smtp.gmail.com"</span>, <span class="string">"*************@gmail.com"</span>,<span class="string">"your_password"</span>);</span><br></pre></td></tr></table></figure></p>
<h2 id="读取收件箱">读取收件箱</h2><p>定义读取gmail收件箱目录。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Folder inbox = store.getFolder(<span class="string">"inbox"</span>);</span><br><span class="line">inbox.open(Folder.READ_ONLY);</span><br></pre></td></tr></table></figure></p>
<h2 id="读取邮件">读取邮件</h2><p>获取到收件箱目录后,就可以很容易的获取到邮件相关的内容了,下面是获取邮件主题的方法。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Message[] messages = inbox.getMessages();</span><br><span class="line">System.out.println(<span class="string">"------------------------------"</span>);</span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < <span class="number">10</span>; i++) {</span><br><span class="line"> System.out.println(<span class="string">"Mail Subject:- "</span> + messages[i].getSubject()); </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h2 id="完整源码">完整源码</h2><p>下面是完整的源码<br><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> class SimpleStoreMails {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> main(<span class="keyword">String</span>[] args) {</span><br><span class="line"> SimpleStoreMails mail = <span class="keyword">new</span> SimpleStoreMails();</span><br><span class="line"> mail.<span class="built_in">read</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="built_in">read</span>() {</span><br><span class="line"> Properties props = <span class="keyword">new</span> Properties();</span><br><span class="line"> <span class="built_in">try</span>{</span><br><span class="line"> props.load(<span class="keyword">new</span> FileInputStream(<span class="keyword">new</span> <span class="built_in">File</span>(<span class="string">"smtp.properties"</span>)));</span><br><span class="line"> Session session = Session.getDefaultInstance(props, null);</span><br><span class="line"> </span><br><span class="line"> Store store = session.getStore(<span class="string">"imaps"</span>);</span><br><span class="line"> store.<span class="built_in">connect</span>(POP3_SERVER, USER, PWD);</span><br><span class="line"> </span><br><span class="line"> Folder inbox = store.getFolder(<span class="string">"inbox"</span>);</span><br><span class="line"> inbox.<span class="built_in">open</span>(Folder.READ_ONLY);</span><br><span class="line"> </span><br><span class="line"> Message[] messages = inbox.getMessages();</span><br><span class="line"> </span><br><span class="line"> <span class="built_in">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < inbox.getMessageCount(); i++){</span><br><span class="line"> Message message = messages[i];</span><br><span class="line"> Date date = message.getSentDate();</span><br><span class="line"> System.out.<span class="built_in">println</span>(<span class="string">"Mail Subject:- "</span> + message.getSubject());</span><br><span class="line"> System.out.<span class="built_in">println</span>(<span class="string">"Mail Content Type:- "</span> + message.getContentType());</span><br><span class="line"> System.out.<span class="built_in">println</span>(<span class="string">"Mail Sent Date:- "</span> + date);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> inbox.<span class="built_in">close</span>(true);</span><br><span class="line"> store.<span class="built_in">close</span>();</span><br><span class="line"> }<span class="built_in">catch</span> (Exception e){</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
]]></content>
<summary type="html">
<![CDATA[<p>年底了,绩效是逃不开的话题,为总结这一年来的工作情况,查看邮件是非常必要的。但是,邮件太多,如何筛选和保留成为一个问题,因此想到实现个自动统计邮件内容的工具,今天分享使用IMAP协议收取gmail邮件的实现方式。<br>]]>
</summary>
<category term="java" scheme="http://yoursite.com/tags/java/"/>
<category term="javamail" scheme="http://yoursite.com/tags/javamail/"/>
<category term="邮件" scheme="http://yoursite.com/tags/%E9%82%AE%E4%BB%B6/"/>
<category term="java" scheme="http://yoursite.com/categories/java/"/>
</entry>
<entry>
<title><![CDATA[登录问题定位过程之unbuntu输入正确密码后重新返回登录界面]]></title>
<link href="http://yoursite.com/2015/12/19/Login/"/>
<id>http://yoursite.com/2015/12/19/Login/</id>
<published>2015-12-19T14:19:11.000Z</published>
<updated>2015-12-20T01:35:08.000Z</updated>
<content type="html"><![CDATA[<p>上周五组内同事搭建了一个jenkins持续集成平台,完善了我们的安卓自动化系统。我们将产品的自动打包集成到里面,当天系统运行正常。周一回来正准备大干一场,突然发现系统无端关机了。OK,关机那就重启吧,半分钟后出现了登录界面,迫不及待的输入密码,[enter],结果界面一闪又重新回到了登录界面。咦!怎么回事?密码是没问题的,再次输入,现象一样!不会吧,难道系统被我们搞坏了?于是开始了长时间的定位过程。<br><a id="more"></a></p>
<h2 id="文件权限问题">文件权限问题</h2><p>google搜索发现跟登录相关的文件是用户根目录下的.Xauthority文件,如果没有这个文件的读取权限就会出现“输入正确密码后重新返回登录界面”的问题。解决方法:</p>
<ul>
<li>ctrl+alt+f1切换到命令行模式</li>
<li>使用正确的用户名密码登录。</li>
<li>在home下查看该文件权限:<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ ls -al .Xauthority</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>很奇怪,执行ls命令提示找不到,说明出问题的机器找不到/bin/ls文件,看来是环境变量失效了,那就自己设定一个环境变量吧,执行以下命令:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">export</span> PATH=/usr/<span class="built_in">local</span>/sbin:/usr/<span class="built_in">local</span>/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/<span class="built_in">local</span>/games</span><br></pre></td></tr></table></figure></p>
<p>再次执行ls命令<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ ls -al .Xauthority</span><br><span class="line">-rw------- 1 staff staff 2727 Mar 21 2015 .Xauthority</span><br></pre></td></tr></table></figure></p>
<p>上述结果显示文件是登录用户staff的,它有读写权限,因此没有问题,排除这种情况。<br>当然如果真的是这个问题可以执行以下命令解决<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo chown staff:staff .Xauthority</span><br></pre></td></tr></table></figure></p>
<h2 id="文件问题(-Xauthority)">文件问题(.Xauthority)</h2><p>继续google我们发现另一种解决办法:</p>
<ul>
<li>ctrl+alt+f1切换到命令行模式</li>
<li>rm -rf .Xauthority</li>
<li>ctrl+alt+f7切换回登录窗口</li>
<li>输入用户名密码登录<br>按照上述方法执行一次,问题依旧,无奈!</li>
</ul>
<h2 id="分析登录日志">分析登录日志</h2><p>以上方法都失效了,继续盲目的google看来意义不大。我们想到了系统日志,说干就干,再次进入命令行模式,查看文件/usr/log/auth.log。<br>通过auth.log的错误日志,我们花了近2小时尝试了很多办法,比较有代表性的解决方案有:<br>(1) 更新系统插件<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ sudo apt-get update </span><br><span class="line">$ sudo apt-get upgrade</span><br></pre></td></tr></table></figure></p>
<p>(2) 将部分系统插件会退到旧版本<br>尝试这两种方法是因为同事说在配置服务器的过程中点击了系统插件的更新,从错误日志中显示可能是插件不兼容导致。<br>(3) 更换桌面,切换成<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ sudo apt-get install xubuntu-desktop</span><br></pre></td></tr></table></figure></p>
<p>怀疑是gnome桌面出问题了,安装新的桌面可以解决这类问题。<br>很不幸的是所有的解决办法都失败了,我们这时快要崩溃了。</p>
<h2 id="回归现象,峰回路转">回归现象,峰回路转</h2><p>在长时间折腾不出解决方案后,我们暂时放弃了,喝喝水并出去溜达了一圈。路上不时的想起定位过程,很快我们注意到第一步中那个奇怪的现象:“ls命令找不到,环境变量实效了!”。我们知道linux启动的时候是默认会初始化环境变量的,即unbuntu默认环境变量中应该会有这个值:<br><figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="regexp">/usr/</span>local<span class="regexp">/sbin:/</span>usr<span class="regexp">/local/</span><span class="string">bin:</span><span class="regexp">/sbin:/</span><span class="string">bin:</span><span class="regexp">/usr/</span><span class="string">sbin:</span><span class="regexp">/usr/</span><span class="string">bin:</span><span class="regexp">/usr/</span><span class="string">games:</span><span class="regexp">/usr/</span>local/games</span><br></pre></td></tr></table></figure></p>
<p>快速回到工位,重启电脑,登录命令行模式,查看机器上的环境变量,执行以下命令:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ /bin/<span class="built_in">echo</span> <span class="variable">$PATH</span></span><br><span class="line">/Users/staff/.jenkins/bin</span><br></pre></td></tr></table></figure></p>
<p>PATH竟然变成了“/Users/staff/.jenkins/bin”。查看jenkins安装指南,我们发现安装过程修改了系统文件/etc/profile,会向这个文件写入jenkins环境变量。查看之:<br><figure class="highlight routeros"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ cat /etc/profile</span><br><span class="line"><span class="built_in">..</span>. (去除不必要信息的干扰)</span><br><span class="line"><span class="attribute">PATH</span>=/Users/staff/.jenkins/bin</span><br></pre></td></tr></table></figure></p>
<p>至此,问题看来已经找到了,linux启动会加载/etc/profile文件配置,因此问题机器PATH会最后修改为“/Users/staff/.jenkins/bin”。而桌面登录时依赖默认的环境变量,因此导致我们输入正确的密码也无法登录。<br>解决方法:将/etc/profile文件中PATH的赋值修改成下列形式。<br><figure class="highlight elixir"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">PATH=<span class="variable">$PATH</span><span class="symbol">:/Users/staff/</span>.jenkins/bin</span><br></pre></td></tr></table></figure></p>
<p>重启机器,输入用户名密码,成功进入系统。</p>
<h2 id="问题总结">问题总结</h2><ul>
<li>定位过程其实走了很多弯路,而关键现象却选择性忽略了,不过借此机会也复习和学习了好些linux相关的配置和命令。</li>
<li>linux系统文件非常敏感,修改时需特别注意<br>系统出问题了,极大的可能是修改了系统文件,因此,一个良好的习惯是系统文件修改前对文件进行备份,然后再进行修改,出问题后直接回滚往往可以马上解决问题。</li>
<li>当问题出现时,先分析全面问题的现象,然后再想解决方案<br>google大法确实很不错,但是如果盲目的搜索只会让问题更乱,折腾的更辛苦。但是如果分析清楚了现象,有时候自直接就能定位出问题,即使依赖google,现象清楚全面,搜索结果也会更加准确,需要1天解决的问题或许1小时(甚至更短时间)就搞定了。</li>
<li>问题定位没有头绪了,暂时抛开,或许会有新思路。<br>苏轼说:“不识庐山真面目,只缘身在此山中”,当我们困扰于问题时,可能我们已经纠结于问题的细枝末节了,而不能看到问题的全貌,这时走出庐山(暂时抛开),从不一样的角度去看它时,往往会有意外的收获。</li>
</ul>
]]></content>
<summary type="html">
<![CDATA[<p>上周五组内同事搭建了一个jenkins持续集成平台,完善了我们的安卓自动化系统。我们将产品的自动打包集成到里面,当天系统运行正常。周一回来正准备大干一场,突然发现系统无端关机了。OK,关机那就重启吧,半分钟后出现了登录界面,迫不及待的输入密码,[enter],结果界面一闪又重新回到了登录界面。咦!怎么回事?密码是没问题的,再次输入,现象一样!不会吧,难道系统被我们搞坏了?于是开始了长时间的定位过程。<br>]]>
</summary>
<category term="linux" scheme="http://yoursite.com/tags/linux/"/>
<category term="unbuntu" scheme="http://yoursite.com/tags/unbuntu/"/>
<category term="登录问题,问题定位" scheme="http://yoursite.com/tags/%E7%99%BB%E5%BD%95%E9%97%AE%E9%A2%98%EF%BC%8C%E9%97%AE%E9%A2%98%E5%AE%9A%E4%BD%8D/"/>
<category term="linux" scheme="http://yoursite.com/categories/linux/"/>
</entry>
<entry>
<title><![CDATA[Linux中/var空间不足的解决办法]]></title>
<link href="http://yoursite.com/2015/10/10/LowSpace/"/>
<id>http://yoursite.com/2015/10/10/LowSpace/</id>
<published>2015-10-10T08:03:29.000Z</published>
<updated>2015-10-10T09:57:39.000Z</updated>
<content type="html"><![CDATA[<p>在Linux的使用过程中,如果/var单独分区,但是指定的空间不大,在更新系统或者安装大型软件(如搭建Discourse论坛平台)的时候,使用到了该目录,就可能导致提示空间不足的情况。本文介绍部分解决办法。<br><a id="more"></a></p>
<h3 id="1-_清理自动安装但不再使用的软件">1. 清理自动安装但不再使用的软件</h3><p>使用以下命令<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get clean</span><br><span class="line">sudo apt-get autoremove</span><br></pre></td></tr></table></figure></p>
<p>autoremove的作用是卸载所有自动安装且不再使用的软件包。<br>autoremove这种方式容易将必要的软件删除掉,尽量不要使用。</p>
<h3 id="2-_使用软链接指向富足的空间区块">2. 使用软链接指向富足的空间区块</h3><p>首先了解下Linux链接的概念。<br>链接是为某一个文件在另外一个位置建立一个不同的链接,分为硬链接和软链接。<br><figure class="highlight excel"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Linux软链接:它只会在你选定的位置上生成一个文件的镜像,不会占用磁盘空间,命令:<span class="built_in">ln</span> -s xxx</span><br><span class="line">Linux硬链接:它会在你选定的位置上生成一个和源文件大小相同的文件,命令:<span class="built_in">ln</span> xxx</span><br></pre></td></tr></table></figure></p>
<p>无论是软链接还是硬链接,文件都保持同步变化。<br>因此,使用软链接可以将/var目录下占用空间较大的目录移动到富足的空间区块(如/home)下,使得/var下不再占用空间。<br>具体实现(www目录为例):<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mv /var/www /home <span class="comment">#将var下的www目录移动到home或者其他空间富足的区块中</span></span><br><span class="line">ln -s /home/www /var <span class="comment">#/var/www指向/home/www,这样www目录将不再占用/var目录的空间</span></span><br></pre></td></tr></table></figure></p>
<h3 id="3-_未单独分区情况">3. 未单独分区情况</h3><p>如果/var没有单独分区,则系统默认共享使用/home目录,若此时提示/var空间不足,则说明/home空间不足,这种情况可以清理一下/home目录或者重新安装系统,重新规划分区结构,当然使用软链接方式也是可以的,只要还有其他空间富足的区块。</p>
]]></content>
<summary type="html">
<![CDATA[<p>在Linux的使用过程中,如果/var单独分区,但是指定的空间不大,在更新系统或者安装大型软件(如搭建Discourse论坛平台)的时候,使用到了该目录,就可能导致提示空间不足的情况。本文介绍部分解决办法。<br>]]>
</summary>
<category term="linux" scheme="http://yoursite.com/tags/linux/"/>
<category term="空间不足" scheme="http://yoursite.com/tags/%E7%A9%BA%E9%97%B4%E4%B8%8D%E8%B6%B3/"/>
<category term="软链接" scheme="http://yoursite.com/tags/%E8%BD%AF%E9%93%BE%E6%8E%A5/"/>
<category term="linux" scheme="http://yoursite.com/categories/linux/"/>
</entry>
<entry>
<title><![CDATA[通过反射创建单例模式的另一个实例]]></title>
<link href="http://yoursite.com/2015/10/05/ReflectionSingleTon/"/>
<id>http://yoursite.com/2015/10/05/ReflectionSingleTon/</id>
<published>2015-10-05T04:09:46.000Z</published>
<updated>2015-10-05T13:07:10.000Z</updated>
<content type="html"><![CDATA[<p>单例模式是最常见的一个模式,在java中单例模式大量被使用。关于单例模式的实现场景可查看<a href="http://hqzhon.github.io/2015/09/30/Singleton/" target="_blank" rel="noopener">java单例模式</a>。今天介绍如何利用反射来创建单例模式的另一个实例,以及枚举实现单例模式规避反射的原理。<br><a id="more"></a></p>
<h2 id="一-_反射创建单例模式的另一个实例">一. 反射创建单例模式的另一个实例</h2><h3 id="1-_实现一个单例模式">1. 实现一个单例模式</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.zhonghq.reflection;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">SingleTon</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> SingleTon instance = <span class="keyword">null</span>;</span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">SingleTon</span><span class="params">()</span></span>{}</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> SingleTon <span class="title">getInstance</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">if</span> (instance == <span class="keyword">null</span>){</span><br><span class="line"> instance = <span class="keyword">new</span> SingleTon();</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> instance;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">single</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"single single"</span>);</span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="2-_使用SingleTon">2. 使用SingleTon</h3><p>我们通过正常方式实例化SingleTon,同时通过反射获取SingleTon的instance,对比它们的地址,如果地址不同就表明另一个实例创建成功。</p>
<p>实现代码如下:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.zhonghq.reflection;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.AccessibleObject;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Constructor;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> <span class="comment">// 正常使用单例模式 </span></span><br><span class="line"> SingleTon singleTon = SingleTon.getInstance();</span><br><span class="line"> System.out.println(<span class="string">"正常使用singleTon:"</span> + singleTon);</span><br><span class="line"> singleTon.single();</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 使用反射获取instance</span></span><br><span class="line"> Class class1 = Class.forName(<span class="string">"com.zhonghq.reflection.SingleTon"</span>);</span><br><span class="line"> Constructor[] constructors = class1.getDeclaredConstructors();</span><br><span class="line"> AccessibleObject.setAccessible(constructors, <span class="keyword">true</span>);</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">for</span> (Constructor c : constructors){</span><br><span class="line"> <span class="keyword">if</span> (c.isAccessible()){</span><br><span class="line"> Object classObject = c.newInstance();</span><br><span class="line"> System.out.println(<span class="string">"反射使用singleTon:"</span> + classObject);</span><br><span class="line"> Method method = class1.getMethod(<span class="string">"single"</span>);</span><br><span class="line"> method.invoke(classObject);</span><br><span class="line"> }</span><br><span class="line"> } </span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>运行,得到以下结果:<br><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">正常使用singleTon:com<span class="selector-class">.zhonghq</span><span class="selector-class">.reflection</span><span class="selector-class">.SingleTon</span>@<span class="number">728</span>edb84</span><br><span class="line">single single</span><br><span class="line">反射使用singleTon:com<span class="selector-class">.zhonghq</span><span class="selector-class">.reflection</span><span class="selector-class">.SingleTon</span>@edf1de</span><br><span class="line">single single</span><br></pre></td></tr></table></figure></p>
<p>可以看到两个地址明显不同,另一个实例创建成功。</p>
<h2 id="二-_枚举方式规避原理">二. 枚举方式规避原理</h2><p>我们同样以代码来查看</p>
<h3 id="1-_实现枚举单例">1. 实现枚举单例</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.zhonghq.reflection;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">enum</span> EnumSingleTon {</span><br><span class="line"> instance;</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">single</span><span class="params">()</span></span>{</span><br><span class="line"> System.out.println(<span class="string">"enum single"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="2-_使用SingleTon-1">2. 使用SingleTon</h3><p>修改示例一中使用SingleTon的代码</p>
<pre><code class="java">Class class1 = Class.forName(<span class="string">"com.zhonghq.reflection.SingleTon"</span>);
</code></pre>
<p>修改为:</p>
<pre><code class="java">Class class1 = Class.forName(<span class="string">"com.zhonghq.reflection.EnumSingleTon"</span>);
</code></pre>
<p>其他不变,运行,结果如下:</p>
<pre><code>正常使用singleTon:com<span class="class">.zhonghq</span><span class="class">.reflection</span><span class="class">.SingleTon</span>@<span class="number">728</span>edb84
single single
Exception <span class="keyword">in</span> thread <span class="string">"main"</span> java<span class="class">.lang</span><span class="class">.IllegalArgumentException</span>: Cannot reflectively create enum objects
at java<span class="class">.lang</span><span class="class">.reflect</span><span class="class">.Constructor</span><span class="class">.newInstance</span>(Constructor<span class="class">.java</span>:<span class="number">521</span>)
at com<span class="class">.zhonghq</span><span class="class">.reflection</span><span class="class">.Main</span><span class="class">.main</span>(Main<span class="class">.java</span>:<span class="number">19</span>)
</code></pre><p>可以看出反射方式执行失败了,抛出了IllegalArgumentException,另一个实例的创建失败。</p>
<p>那么为什么呢?<br>查看异常我们发现问题出在代码Object classObject = c.newInstance(); 该代码是使用java.lang.reflect.Constructor的newInstance()方法实现的,查看该方法的实现我们发现其禁止了通过反射构造枚举对象,代码如下;</p>
<pre><code class="java"><span class="keyword">if</span> ((clazz.getModifiers() & Modifier.ENUM) != <span class="number">0</span>)
<span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Cannot reflectively create enum objects"</span>);
</code></pre>
]]></content>
<summary type="html">
<![CDATA[<p>单例模式是最常见的一个模式,在java中单例模式大量被使用。关于单例模式的实现场景可查看<a href="http://hqzhon.github.io/2015/09/30/Singleton/" target="_blank" rel="noopener">java单例模式</a>。今天介绍如何利用反射来创建单例模式的另一个实例,以及枚举实现单例模式规避反射的原理。<br>]]>
</summary>
<category term="java基础" scheme="http://yoursite.com/tags/java%E5%9F%BA%E7%A1%80/"/>
<category term="Singleton" scheme="http://yoursite.com/tags/Singleton/"/>
<category term="单例模式" scheme="http://yoursite.com/tags/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/"/>
<category term="反射" scheme="http://yoursite.com/tags/%E5%8F%8D%E5%B0%84/"/>
<category term="java基础" scheme="http://yoursite.com/categories/java%E5%9F%BA%E7%A1%80/"/>
</entry>
<entry>
<title><![CDATA[java单例模式(Singleton)]]></title>
<link href="http://yoursite.com/2015/09/30/Singleton/"/>
<id>http://yoursite.com/2015/09/30/Singleton/</id>
<published>2015-09-30T08:09:46.000Z</published>
<updated>2015-12-04T12:29:50.000Z</updated>
<content type="html"><![CDATA[<p>最近在测试的时候遇到几个关于多线程的问题,其实频繁涉及单例模式相关的问题,因此翻看文章和资料总结了本篇文档,做为后续的学习和工作参考。<br><a id="more"></a></p>
<h2 id="一-_单例模式简介">一. 单例模式简介</h2><h3 id="单例模式是用来创建独一无二的,只有一个实例的对象的模式-使用单例模式创建一个模型,它确保只产生一个实例,并提供一个访问它的全局访问点。">单例模式是用来创建独一无二的,只有一个实例的对象的模式.使用单例模式创建一个模型,它确保只产生一个实例,并提供一个访问它的全局访问点。</h3><h3 id="1-_为什么使用单例模式?">1. 为什么使用单例模式?</h3><p>部分对象使用过程中只能有一个实例,如果制造出多个,会导致很多问题,如程序的行为异常,资源使用过量和数据不一致的情况。</p>
<h3 id="2-_静态变量实现单例的缺点">2. 静态变量实现单例的缺点</h3><p>静态全局变量可以实现单例,但是这样必须在程序一开始就创建好对象,如果对象创建非常耗时,这会导致程序初始化过慢,同时如果执行过程中没有使用过,也会导致资源的浪费。</p>
<h3 id="3-_单例模式应用场景">3. 单例模式应用场景</h3><p>(1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如日志文件,应用配置。<br>(2)控制资源的情况下,方便资源之间的互相通信。如线程池,缓存等。</p>
<h2 id="二-_六种单例模式实现">二. 六种单例模式实现</h2><h3 id="1-_懒汉">1. 懒汉</h3><p>线程不安全的写法。<strong>懒汉式是典型的以时间换空间</strong>,每次获取实例都会判断,看是否需要创建,浪费判断的时间。而如果没有人使用的话,就不会创建,节省了内存空间。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Singleton</span> </span>{ </span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Singleton instance; </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Singleton <span class="title">getInstance</span><span class="params">()</span> </span>{ </span><br><span class="line"> <span class="keyword">if</span> (instance == <span class="keyword">null</span>) { </span><br><span class="line"> instance = <span class="keyword">new</span> Singleton(); </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">return</span> instance; </span><br><span class="line"> } </span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">Singleton</span> <span class="params">()</span></span>{} </span><br><span class="line"> }</span><br></pre></td></tr></table></figure></p>
<p>线程安全的写法,但是效率很低<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Singleton</span></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Singleton instance;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> Singleton <span class="title">getinstance</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">if</span> (instance == <span class="keyword">null</span>){</span><br><span class="line"> instance = <span class="keyword">new</span> Singleton();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> instance;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">Singleton</span><span class="params">()</span></span>{}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h3 id="2-_饿汉">2. 饿汉</h3><p>类加载时直接初始化,如果不使用而提前创建会耗用性能。 <strong>饿汉式是典型的空间换时间</strong>,当类装载时会创建类的实例,不管你用不用,先创建出来,然后每次调用的时候不需要再判断,节省了运行时间。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Singleton</span> </span>{ </span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Singleton instance = <span class="keyword">new</span> Singleton();</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Singleton <span class="title">getInstance</span><span class="params">()</span> </span>{ </span><br><span class="line"> <span class="keyword">return</span> instance; </span><br><span class="line"> } </span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">Singleton</span> <span class="params">()</span></span>{} </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h3 id="3-_双重校验锁">3. 双重校验锁</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Helper</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Helper helper = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Helper <span class="title">getHelper</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (helper == <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">synchronized</span>(<span class="keyword">this</span>) {</span><br><span class="line"> <span class="keyword">if</span> (helper == <span class="keyword">null</span>)</span><br><span class="line"> helper = <span class="keyword">new</span> Helper();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> helper;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>首先判断instance是不是为null,如果为null,加锁初始化;如果不为null,直接返回instance。</p>
<p>但是这个方法在单核和多核的cpu下都不能保证很好的工作。问题是由编译器优化导致。编译器优化是指在不改变原来语义的情况下,通过调整语句顺序,来让程序运行的更快。</p>
<p>回到问题,创建对象是非原子操作,会经历如下过程:<br> 1,申请内存,调用构造方法初始化;<br> 2,分配一个指针指向这块区域。<br>这两个操作JVM并没有规定谁先执行,编译器优化过程中就可能导致JVM是先开辟出一块内存,然后把指针指向这块内存,最后调用构造方法进行初始化。从而出现以下问题:<br> 1、线程A进入getHelper()方法;<br> 2、因为此时helper为空,所以线程A进入synchronized块;<br> 3、线程A执行 helper = new Helper(); 先将helper指向一块内存,此时helper已经非空,而并未初始化;<br> 4、同时线程B进入,检查helper不为空,则直接使用这个实例并使用,如果此时helper还为初始化完成就会出现问题。</p>
<p>为解决以上问题,有以下尝试:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Singleton</span> </span>{ </span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Singleton instance = <span class="keyword">null</span>; </span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Singleton <span class="title">getInstance</span><span class="params">()</span> </span>{ </span><br><span class="line"> <span class="keyword">if</span> (instance == <span class="keyword">null</span>) { </span><br><span class="line"> Singleton sc; </span><br><span class="line"> <span class="keyword">synchronized</span> (Singleton.class) { </span><br><span class="line"> sc = instance; </span><br><span class="line"> <span class="keyword">if</span> (sc == <span class="keyword">null</span>) { </span><br><span class="line"> <span class="keyword">synchronized</span> (Singleton.class) { </span><br><span class="line"> <span class="keyword">if</span>(sc == <span class="keyword">null</span>) { </span><br><span class="line"> sc = <span class="keyword">new</span> Singleton(); </span><br><span class="line"> } </span><br><span class="line"> } </span><br><span class="line"> instance = sc; </span><br><span class="line"> } </span><br><span class="line"> } </span><br><span class="line"> } </span><br><span class="line"> <span class="keyword">return</span> instance; </span><br><span class="line"> } </span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">Singleton</span><span class="params">()</span> </span>{ } </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>看起来这种方式可以解决问题,但是这种想法完全是错误的!同步块的释放保证在同步块里面的操作必须完成,但是并不保证同步块之后的操作不能因编译器优化而调换到同步块结束之前进行。因此,编译器完全可以把instance=sc;这句移到内部同步块里面执行。这样,程序又是错误的了!</p>
<h3 id="4-_双重校验锁问题解决方案">4. 双重校验锁问题解决方案</h3><p>在JDK 5之后,Java使用了新的内存模型。volatile关键字有了明确的语义——在JDK1.5之前,volatile是个关键字,但是并没有明确的规定其用途——被volatile修饰的写变量不能和之前的读写代码调整,读变量不能和之后的读写代码调整!因此,只要我们简单的把instance加上volatile关键字就可以了。关于volatile关键字分析可参考文章<a href="http://www.cnblogs.com/dolphin0520/p/3920373.html" target="_blank" rel="noopener">Java并发编程:volatile关键字解析</a>。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Helper</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">volatile</span> Helper helper = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Helper <span class="title">getHelper</span><span class="params">()</span> </span>{</span><br><span class="line"> Helper hp;</span><br><span class="line"> <span class="keyword">if</span> (hp == <span class="keyword">null</span>) {</span><br><span class="line"> hp = helper;</span><br><span class="line"> <span class="keyword">synchronized</span>(<span class="keyword">this</span>) {</span><br><span class="line"> <span class="keyword">if</span> (helper == <span class="keyword">null</span>)</span><br><span class="line"> helper = <span class="keyword">new</span> Helper();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> helper;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h3 id="5-_内部类实现">5. 内部类实现</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Singleton</span></span>{</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类级内部类的实例和外部类的实例没有绑定关系,而且只有在被调用到时才会装载,从而实现延迟加载。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">InnerSingleton</span></span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Singleton instance = <span class="keyword">new</span> Singleton();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Singleton <span class="title">getinstance</span><span class="params">()</span></span>{</span><br><span class="line"> <span class="keyword">return</span> InnerSingleton.instance;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">Singleton</span><span class="params">()</span></span>{}</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟饿汉方式不同的是:饿汉方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为InnerSingleton类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载InnerSingleton类,从而实例化instance。</p>
<p>想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。</p>
<h3 id="6-_枚举实现">6. 枚举实现</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">enum</span> Singleton{</span><br><span class="line"> instance;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">do</span><span class="params">()</span></span>{}</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象</p>
<p>参考文档: <a href="http://cantellow.iteye.com/blog/838473" target="_blank" rel="noopener">单例模式的七种写法</a> , <a href="http://devbean.blog.51cto.com/448512/203501/" target="_blank" rel="noopener">深入Java单例模式</a> , <a href="http://book.douban.com/subject/2243615/" target="_blank" rel="noopener">head first设计模式</a></p>
]]></content>
<summary type="html">
<![CDATA[<p>最近在测试的时候遇到几个关于多线程的问题,其实频繁涉及单例模式相关的问题,因此翻看文章和资料总结了本篇文档,做为后续的学习和工作参考。<br>]]>
</summary>
<category term="java" scheme="http://yoursite.com/tags/java/"/>
<category term="Singleton" scheme="http://yoursite.com/tags/Singleton/"/>
<category term="单例模式" scheme="http://yoursite.com/tags/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/"/>
<category term="多线程" scheme="http://yoursite.com/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/"/>
<category term="java基础" scheme="http://yoursite.com/categories/java%E5%9F%BA%E7%A1%80/"/>
</entry>
</feed>