[問題] 有沒有人碰過所謂的靈異現象
抱歉,"靈異現象"一詞是敝公司內部在用的
主要是講各種 執行不如預期
通常,有很大機率,會被人說"那是你自己寫程式不小心"
比如,程式在不該當的地方當了
但怎麼查也查不到原因
其實原因是更早之前使用了不存在或已刪除的變數
(這狀況在 java 還沒碰過;我是舉 C 的例子)
因為無效指標會讓程式流程跑到亂碼
也可能破壞堆疊;而且不一定"馬上"當
不過這次的例子比較奇怪
主管已經追一個禮拜了
(幸好不是發生在我身上,不然一定罵死我又不相信我
發生在他身上,他則說"解決了有賞"XD)
public void run() {
long __lCurrentTime = 1466154837;
long __lTimeout = __lCurrentTime + 6;
boolean __result = false;
// 中斷點1:請在下一行放置一個中斷點
int __count = 0;
for ( ; __lCurrentTime<=__lTimeout ; __lCurrentTime++) {
__result = __lCurrentTime<=__lTimeout;
__count++;
}
// 中斷點2:請在下一行放置一個中斷點
}
這次的例子是上面的小程式
中斷點 2 永遠執行不到
而檢查 __result, 也竟然永遠為 true
自己直接把程式放入自己的小專案當然沒問題
我們這個是放在敝公司的專案中
而奇怪的是,它還挑 build machine
這段 code 要在特定機器上 build 出 APK
才會執行不完
其他機器去 build, 則不會執行出問題
(而我們信任自己的 build machine 啊,那是裝好後只用來 build 程式的一台專用機器)
重灌 build machine 嗎?也不對,因為不只一台會出問題
(會出問題的就一直 build 出問題)
程式的邏輯很簡單(雖然不實用;因為它是專為了重製問題,簡化出來的 code)
同事因此做了個猜測:堆疊炸了
如果堆疊炸了,那當然程式就不必談邏輯了
但這段程式是位在另一個 thread, 同事加大 thread stack
new Thread(null, null, TAG, 2*1024*1024)
沒有用
主管現在用另一個方法迴避問題
把原來的 long, 故意 cast 成 double
這樣是很無聊啦,但 compare 結果會正確了!!
(如果是堆疊炸了,應該要減少使用自動變數才對
奇奇怪怪的迴避方法未必能解決問題吧!)
同事說,這種奇怪的問題,未必能用以前 C/C++ 時的邏輯去猜想
可能要更深入 byte code 去推斷
請問有沒有人解過類似的問題
(這不像 java 語法問題,而是 java 環境使用上的問題)
謝謝
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 60.251.197.55
※ 文章網址: https://www.ptt.cc/bbs/java/M.1466485086.A.EF4.html
推
06/21 18:18, , 1F
06/21 18:18, 1F
→
06/21 18:18, , 2F
06/21 18:18, 2F
__lCurrentTime 會漸漸變大,而它比起另一個變數,只大6
因此這個 forloop 執行六次左右就該結束
結束時 __lCurrentTime<=__lTimeout 這個判斷條件應為 false
而 __result 應該不會被更新到
目前的問題就是不結束,__result 永遠為 true
我應該沒寫錯
→
06/21 19:08, , 3F
06/21 19:08, 3F
我常在板上挨罵就算了,他們可資深得不得了
工研院出來的,Trace 過整個 Unix,
我會懷疑他們在 java 上的功力,畢竟碰沒多久
但不會懷疑他們在 c/c++, multi-thread 的功力 (因為也曾是 multithread 講師)
因此比如變數被另一個 thread 干擾,這個也排除了
我自己前陣子是解掉一個,原因就是 multi-thread
變數 a 的值,我一直 trace 都是我要的,突然一轉眼就變了
但是同事避這個問題的方法很簡單:他沒必要共享變數,他的是 local 變數
既然變數沒被另一個 thread 參考到,那值就沒有變的理由
那為什麼會出現像
boolean a = (5 <= 3);
結果 a 為 true, 這樣很根本上的錯誤呢?
-------------------
問題可能解掉了
方法是把一個四千多行的函式縮小,拆成數個
因此目前我們只能認為,這也是 java 的極限
(我不是說不能寫四千多行喔,別自己去寫一個四千多行的來打我臉,不是這樣喔)
麻煩的就是,既然炸了也好歹打聲招呼,丟個 fatal 出來
都沒有啊,默默的...
那我們就有一堆不確定的猜測,大量的測試
操死一堆同事...
※ 編輯: HuangJC (60.251.197.55), 06/21/2016 19:26:31
推
06/22 00:21, , 4F
06/22 00:21, 4F
→
06/22 00:21, , 5F
06/22 00:21, 5F
→
06/22 11:44, , 6F
06/22 11:44, 6F
→
06/22 11:58, , 7F
06/22 11:58, 7F
→
06/22 11:59, , 8F
06/22 11:59, 8F
→
06/22 12:00, , 9F
06/22 12:00, 9F
→
06/22 12:06, , 10F
06/22 12:06, 10F
→
06/22 12:09, , 11F
06/22 12:09, 11F
→
06/22 12:11, , 12F
06/22 12:11, 12F
→
06/22 12:11, , 13F
06/22 12:11, 13F
推
06/22 12:16, , 14F
06/22 12:16, 14F
推
06/22 12:16, , 15F
06/22 12:16, 15F
→
06/22 12:30, , 16F
06/22 12:30, 16F
→
06/22 12:30, , 17F
06/22 12:30, 17F
→
06/22 12:30, , 18F
06/22 12:30, 18F
→
06/22 13:05, , 19F
06/22 13:05, 19F
→
06/22 13:05, , 20F
06/22 13:05, 20F
→
06/22 13:08, , 21F
06/22 13:08, 21F
→
06/22 13:09, , 22F
06/22 13:09, 22F
→
06/22 13:11, , 23F
06/22 13:11, 23F
→
06/22 13:11, , 24F
06/22 13:11, 24F
→
06/22 14:08, , 25F
06/22 14:08, 25F
→
06/22 16:00, , 26F
06/22 16:00, 26F
→
06/22 16:01, , 27F
06/22 16:01, 27F
→
06/22 16:03, , 28F
06/22 16:03, 28F
→
06/22 16:17, , 29F
06/22 16:17, 29F
→
06/22 16:17, , 30F
06/22 16:17, 30F
我文章從頭到尾都說和build machine 有關啊,換一台就不會
從前我做 embedded system 時
用的 cross compiler 很讓人懷念
那是一個只要一模一樣的 source code 進去
build 出來的 bin 就會一模一樣的 compiler
因此,每當我拿到一台新的電腦,重架起 compiler 時
第一件事,就是 build 一下我們最新的 release
拿到結果後做 file compare, 一定要一模一樣
若沒一模一樣,就一定有錯
又比如,加入新 model, 新功能
而同一個 code 要 build 舊 model
code 已經有變了,要證明沒影響舊 model
也是 build 一版出來做 file compare
像現在這個問題,特定 build machine 有問題
其實我是很想說"就那台 build machine 自己有問題啦"
但不只一台會
因此如果沒找到問題,有個合理假設
換台機器 build 仍然只會被認為是頭痛醫頭腳痛醫腳而已
※ 編輯: HuangJC (60.251.197.55), 06/22/2016 16:34:28
→
06/22 16:37, , 31F
06/22 16:37, 31F
→
06/22 16:38, , 32F
06/22 16:38, 32F
__lCurrentTime = 1466154837;
__lTimeout = __lCurrentTime + 6
跑數次後, __lTimeout 沒變
__lCurrentTime 變成 1446154850
然後 __result = __lCurrentTime<=__lTimeout;
這個 __result 依然是 true
這樣大家感覺到問題沒有?
當然我自己不會這樣寫程式
我認為如果是記憶體錯亂,那麼 for loop 裡的布林值和算式裡的布林值,就未必結果相同
真的要龜毛,必需這樣寫
for ( ; __result = (__lCurrentTime<=__lTimeout) ; __lCurrentTime++) {
Log.v(TAG, __result);
__count++;
}
也就是一定要和 forloop 的判斷式,用同一個
看到底是 boolean 不如預期
還是明明為 false 了但卻不往外跳
不管哪一個,其實都是執行不如預期
但我覺得這樣會更精準點
這已經不是語言邏輯層次的問題,我其實見過很多次
文章前面也說了:當記憶體配置出問題,那就見怪不怪了
java 用的是 GC,而不像 C 要由工程師自己去管理記憶體,new & delete
因此在 GC 極強的記憶體管理下
我其實還不太清楚怎麼造出以前的狀況
在 C,這種問題可以說是層出不窮,都是要去檢討有沒有做了違犯規定的存取..
※ 編輯: HuangJC (60.251.197.55), 06/22/2016 16:45:12
→
06/22 16:45, , 33F
06/22 16:45, 33F
→
06/22 16:45, , 34F
06/22 16:45, 34F
→
06/22 16:45, , 35F
06/22 16:45, 35F
還有 35 則推文
還有 6 段內文
→
06/22 17:36, , 71F
06/22 17:36, 71F
→
06/22 17:37, , 72F
06/22 17:37, 72F
→
06/22 17:37, , 73F
06/22 17:37, 73F
有 log 它沒錯
→
06/22 17:37, , 74F
06/22 17:37, 74F
※ 編輯: HuangJC (60.251.197.55), 06/22/2016 17:38:02
題外話,在以前寫 C 時,我碰過另一個靈異現象
void F2() { a = 5; }
void F1() {
F2();
a = 6;
a = 7;
.
.
.
}
如上,F2 是幫忙設一些初始值
接下去 F1 的片段是開始修改那些值
可是我發現那些值一直跳回來
比如上例的 a, 明明後續設為 6, 設為 7
但監控它會發現它一直是 5
我全域搜尋 a 何時被改為 5,只有 F2 裡有做這件事
後來忍不住了,在 F2 開頭下一個中斷點
結果發現,F1 "每執行一行",就會跳去執行 F2 一次
程式裡完全看不出來,但執行結果就是這樣
那次我加班到凌晨都解不掉
幸好第二天,主管說那個案子不做了
我真的感覺莫名其妙
不管重開機,clean build
種種能把環境弄乾淨的方法我都試了
但我就是不知道,誰奪取了控制權,硬去執行 F2 的
那種感覺就像陷入了單步中斷
debugger 就會做這種事
但那是 VC 的特權,誰搶去做了?
※ 編輯: HuangJC (60.251.197.55), 06/22/2016 17:49:37
→
06/22 17:59, , 75F
06/22 17:59, 75F
→
06/22 18:00, , 76F
06/22 18:00, 76F
這要講兩支程式,一支是線上實際出貨的
這個有看所有變數
另外一個是為了縮小測試範圍,所以簡化(但仍然可以重製 bug)
公開在板上的是這支程式
這支程式裡已經沒有 log 了
我也不可能用步進執行
因為,一但步進執行,就是在我的機器上重 build
(不重 build 但又可以步進執行,以前 code view 玩過,現在在 android 我還沒試過)
而我們強調是'那一台特定 build machine 才會有問題'
公開的這一支,同事只說,永遠執行不到第二個中斷點
endless loop
這句話,和實際出貨的程式倒是一樣
QA 測到的就是迴圈跑不完;但比較值已經遞增到極大了,為什麼還不結束 loop?
(比較值及被比較值,兩者都有 log)
我是很想參戰啦,但我沒重製過問題
我參戰的必要條件是:讓我可以操作 build machine,任意 build 我改的 code
這點,沒法子
大家煩得要死,不給我玩
--------------
我們出貨的程式,不是任意 RD 電腦 build 出來都可以出
而是特定的 build machine
它一連串的批次動作,從取 code, build, 到包裝成出貨 package 放至特定子目錄
(子目錄名稱和時間日期相關)都是自動化的
我無法把我的 code 塞給它,除非我 check in code
他們不給我玩啦..
所以,謝謝大家,警察可以出來洗地了...
※ 編輯: HuangJC (60.251.197.55), 06/22/2016 18:15:49
推
06/22 18:15, , 77F
06/22 18:15, 77F
→
06/22 18:15, , 78F
06/22 18:15, 78F
→
06/22 18:15, , 79F
06/22 18:15, 79F
→
06/22 18:15, , 80F
06/22 18:15, 80F
→
06/22 18:15, , 81F
06/22 18:15, 81F
→
06/22 18:15, , 82F
06/22 18:15, 82F
→
06/22 18:15, , 83F
06/22 18:15, 83F
→
06/22 18:15, , 84F
06/22 18:15, 84F
但我有說,這段程式,要放在我們程式內
我不想怪你沒爬文耶,我是來請教大家的,要有禮貌 :P
→
06/22 18:15, , 85F
06/22 18:15, 85F
會超過 :P
※ 編輯: HuangJC (60.251.197.55), 06/22/2016 18:18:22
→
06/22 18:35, , 86F
06/22 18:35, 86F
→
06/22 18:36, , 87F
06/22 18:36, 87F
→
06/22 18:37, , 88F
06/22 18:37, 88F
→
06/22 18:38, , 89F
06/22 18:38, 89F
→
06/22 18:38, , 90F
06/22 18:38, 90F
→
06/22 18:39, , 91F
06/22 18:39, 91F
for ( ; ; __lCurrentTime++) {
__result = (__lCurrentTime<=__lTimeout);
Log.v();//__result, __lCurrentTime, __lTimeout 三個都要看
//一次就能讓大家標定問題
if ( !__result )
break;
}
這樣更龜毛
問題應該可以限縮至"為什麼 long compare 出錯了"
※ 編輯: HuangJC (60.251.197.55), 06/22/2016 19:09:55
→
06/22 19:10, , 92F
06/22 19:10, 92F
→
06/22 19:10, , 93F
06/22 19:10, 93F
→
06/22 19:11, , 94F
06/22 19:11, 94F
→
06/22 19:12, , 95F
06/22 19:12, 95F
推
06/22 19:51, , 96F
06/22 19:51, 96F
→
06/23 00:14, , 97F
06/23 00:14, 97F
→
06/23 11:45, , 98F
06/23 11:45, 98F
→
06/23 11:45, , 99F
06/23 11:45, 99F
→
06/23 12:41, , 100F
06/23 12:41, 100F
→
06/23 12:41, , 101F
06/23 12:41, 101F
→
06/23 12:41, , 102F
06/23 12:41, 102F
→
06/24 14:56, , 103F
06/24 14:56, 103F
→
07/01 12:41, , 104F
07/01 12:41, 104F
java 近期熱門文章
PTT數位生活區 即時熱門文章