▲Collatz Tree GeneratorのDegree欄に大きな数字を入力して,メモリ不足エラーのパネルが表示された後の動作が悪い.画面が薄色のハング状態になっている.⇒再現しない.というか,開発環境ではメモリ不足ではなく先に整数レンジオーバーが発生している.サブノートではもっとずっと小さい数で障害が発生する.Degreeに1111111を入力してGoでエラーも出さずにハング状態になる.おそらくメモリ不足状態と思われるが,かなりまずい.開発環境では長整数の範囲ならほぼ無制限に動作してしまうため,再現できない.現在でもぎりぎりというところなので,サブノートにVSをインストールするのはかなりしんどい.
しかし,エラーも出さずにハングというのはかなり問題だ.サブノートは元々メモリが乏しいところにLibreやOpen Live Writerなどを開いているので逼迫しているのだろう.メモリ3.9GBのところ,46%使用して残り1.8GB,開発環境では15.7GBの36%を使用して残り5.6GBというところだ.何か余分なアプリを起動して追い込むことはできるだろうか?VS2017を立ち上げたら逆に空き容量6.4GBと増えてしまった.いや,読み違えている.数字は空き容量ではなく,使用中メモリ量だ.VS2017とVS2019を複数個立ち上げてデバッグモードで走らせてみた.再現できそうだ.メモリ使用量10.4/15.7GB(66%)という状態だ.
CollatzTreeStructureという再帰関数の中でハングしている模様だ.ハングしているというより,応答に時間が掛かっているということだろうか?⇒ここでは一行分の分岐枝リストを作成しているので,1111111個ものリストを作るのに手間取っているようだ.しかし,開発環境ではこれより遥かに大きい数字を与えても楽々と走っているので,メモリが不足しない限り時間的には問題は生じていない.起動していたプログラムを終了させてほぼ初期状態にまで戻したが,回復しない.ただし,ハングしている訳ではない(ループは回っているが,解放されたメモリの割当が回ってこないようだ)
このような状況を回避するためには,最初にメモリ容量をチェックして処理に入らないようにするしかないような気がするが…仮想記憶と実メモリの間でスラッシングが起きているようだ.一度このトラップに堕ちると這い出せないようになる.⇒ループの中にDoEventsを入れてみた.これで,少なくともMax numberが更新されるようになったので,システムが停止していないことだけは目に見えるようになった.これしかないのではないか?Degreeが1111111になると,扱う数字も巨大なものになるので,バッファサイズも半端なものではなくなる.
Stopボタンは応答したが,処理は停止しない.ループから脱出する機構がないからだ.ループの中でStopFlagを見るようにした.Quitボタンも効くようになった(2度押しする必要がある)
▲Tree heightに1111111を入力してGoで「BigInteger cannot represent infinity」というエラーになった.Max node countがオーバーフローしているのではないか?MIN = System.Math.Pow(D, H) / 3 + System.Math.Pow(D + 1, 3)という計算の中でエラーが発生しているようだ.しかし,これより大きい計算でエラーが出ていないのだが…⇒計算式が違う.一方はBigIntegerの関数を使い,他方ではSystem.Mathの関数を使っている.System.Mathを使ったのは,べき乗に実数値を使う意図があったためではないかと思われる.
動作するようにはなったが,Max node countとVoid node countは空欄になっている.テキストボックスの範囲を超えているのだろうか?⇒Max tree heightが60台でこんなに遅くなるのも疑問だ.しかも,停止しているはずなのにまだ動作しているように見える.「The value could not be parsed」というエラーまで出た.StopFlagは立っていない.GoボタンのラベルはGoに戻っているので,停止していなくてはならないのだが,おそらくStopFlagのリセットがループからの脱出より先に来てしまったのに違いない.どこかで待ち合わせする必要があるのだろうか?それもかなり厄介な話だ.
テキストボックスの最長文字列は32767になっている.Int16だ.Max node countとVoid node countの最長文字列をInt32の上限の2147483647にしてみた.しかし,Tree height は11111以上にできない.樹高が11111のときのMax node countの値は,以下のような巨大数だ.しかし,それにしてもInt32の上限に達しているようには思われない…実質的にはInt16で切られているのではないだろうか?
2953605235887922076986378442975100733421380433595488436437675563862279339636402284171077108640824492567945743660848308432773274251758294134422272781393529260708423985567074562376453698742113143788729790540670032661983383583264784373515863947681418431231600872837603844688035862251750065151097207961708009175997851643046165387328678207210679516050903812546334558591851764497664676434996294739662557148059693600289454149489147537316076690357353342068905966545282831648439149007479683084332895809064434398262904074105454182349778021798603400218224012863909260258462677169061262207288629959430375345537969555899094212302491008931013324401565581391038230449877641472497396251209333870828659780033640482414624459293308630820964721219830209788127320707309301681050799520792563039769351003070781921104941811308840451608085583180556595173507563999097055183333070730416445616170775220884250852997371330663007063757479850908482270876120591837949660659133837577438463791152489190083042247316022362886246805301711608002272205422719760380408437671657032815750474487423483498363174469587702435709535117807694637079869252054221254536755904380380985252727687649666702323026878447758068804635813294095679985543884226912628994953823505112046464129504178964133835215465031774986825229329761879793655236633325596314044479287971111236288766804874934999938484483937562652945979258855713992445279787472903892281958917369815092346326602772090535995278792584898576568153322660990794248744827214825337234481591700169509140254358089227959966817229151527837339001885588119162292660200830769862465716148422912721579573038694948415443492285328166231082320350059283262652985674275598722661958799384211057329107359791498334557558560258714734439979843307793166639365444986518526924384730689227896436396096357395407544931568582924892540786158542235973075609676537844404439600687921946142907192647614499377349848850513517788008144494605654547439690629060631724088751397606044320763618365145817682733085421083431774025971183090722932894166629388596212316160143319795602912480175075409572386253590500334523171706468488045531728011595893150716261348543344640166810158266971949803948342139650655350564626451329461151437822257367066847250992798971329661941975427279965603581351442701086297157300538857447608584554143292165350648005988680626688349013866643831271709858946053565730983856077081716030583714950887817203845332638278612891501472276916864209046254611194222890041834666609541019595133400489876280631300134821296089683541508426428594268228575225420579612130414488621064249863966431842166639318773020289801201248366877754830826448862809207535850691295043275358832481115753621755050417391468028791428843327503991373967071851724262628069792791065793134175244348237391306264487253705979319157311567888600768540933159629065962995209389368546347265876253769080008598829898780872014395921395727278532600477043952800427889864968443913001038657282221865623607645562360730736414508951615648092518934014281607239894179623091424511251115337104605065839496302258322185897396815351399498349920264296496134618678347372408304966280634973683448066379905815275840324070164174242809779422497980171988148842731872181629065283717474788073878450911239741425222249958904900692783463476747864375695613682259325270526249118724337466530615938656708130291862191416740689565391094635610051841433240092405122156874017910491182033892260220441100264507685824802444484621594701088592785835096120216514057502113076922130743203033833069070028073141574063721534019564154479990326717129311132662935426153909541359843848917140940551876132675219100118915889607335646451806654176630835860564184272993298885348106439939578851127338437684802282058581358868794086951785329107919027811250248110746858060524232666133190458093064491349488686944036427745131309511175361984018759355978415336382054185991527706132765928119294414252004883948864008920559325937149217599625315043322613614393523978796623311588863968094289173510990083408051502486424871471964517627477082203831670190482657688399190838923813657762032472370166556571429057199444408246965460008497381707035856540193640021018820983604136075328275010888926432709885422710734969202215047088553751198230025881935299085760864791201519439182988748575126920778498827087113284245484151598692958763612311165248724519642793982683222470278785737605066963638496108060614540655520591242769528306037560838304489683930072041808655325046364233006472164787060631355845656133693737601430524816677695199872457304163426405676813700516660168836966244165750847437239372169049314609601750384916934753863323201898860653937841928677798135923683817633828305142429696075932838623304791581633313873877280091778676006497945320722607622547438850541848185106481101488583987172006668154747455829415798455013034774418900843038862678955383301601531678406267258173795652512152421235416421647198531819646250017299304404970241298175160691377235910976425551378432785749376613742284507244792812213890223878080463244824786378920987086789507258558505600283857905639541827286114346438894763810209179694695250275930809802266340778340070866781411418432407505324767755570085460106365991790678933763476949878705506609504313910548052486237255855035208105862462188254027577531060106970782819991599365065699230421487997765939432354565453872215039358770395720050317565976720
これは表示されないというだけで,動作的には問題はないが…Tree height=11111でスタックオーバーフローが発生した.しかし,エラーハンドラに制御が渡ってこない.この後,直ちにアボートしてしまうので実害はないとは言え,エラーメッセージが出ないのは不都合だ.
テキストボックスの表示桁数は元の32767に戻した.障害はRichTextのテキストの切り詰めを実施しようとするところで起きている.⇒開発環境ではTree height=461でスタックオーバーフローが発生する.しかし,不思議なことにサブノートでは同じ設定で走り続けている…いや,一度開発環境を落として再起動したら走るようになった.しかし,472では起きる.471なら走るようだ.
on error goto を廃止してtry catchに変えたら動作するようになった.いや,同じだ.CollatzTreeStructureが復帰するところでBranchlist = vbNullを実行するようにして少し動作するようになったが,482で止まる.これ以上はどうしようもない感じがする.480が上限だ.DoEventsが負荷になっている可能性もある.スタックのデフォルトサイズは1MBとなっているようだ.
いや,どうもどこかで修正ミスをしている可能性もある.サブノートでは500という設定で問題なく走っている.一度バックアップに戻って見直してみることにする.⇒どうも状況がつかめなくなってきた.サブノートでは500で走っているのに,開発環境では停止してしまう.一つ前のバージョンに戻ってみたが,同じだ.1月13日バックアップという版では1000では走ったが,10000では落ちた.どうしたらよいか?ソースを比較するために,WinMergeをダウンロードしてみる.日付は異なるが,内容はまったく同じだ.ということはEXEで走るか,デバッグモードで走るかの違いだけということになる.⇒確かにそのようだ.つまり,EXEと開発環境ではスタックサイズが異なるということになる.
EXEでは,1410で落ちた.つまり,そこでスタックオーバーフローが発生したということだろう.せめて,5000くらいまでは黙って走ってもらいたいのだが…デバッグモードでは481で停止する.EXEをeditbinで直接操作してスタックを増やすという手はあるようだ.ビルド中にそれができるとよいのだが…ポストビルドイベントに以下のようなコードを入れてみた.
"$(DevEnvDir)..\..\VC\bin\editbin.exe" /STACK:8388608 "$(TargetPath)"
何も警告は出ていないので動作していると思われるのだが,効果なし.⇒できた.構文が悪かったようだ.7767まで進んでアボートした.再帰実行に入る前にodd配列を空にするようにしてみたが,まったく効果なし.分岐枝リストをパージするのは効果があるようだ..特に時間効率に影響する.⇒修正箇所は元に戻した.現在の設定値8388608を2^32=4,294,967,296まで上げてみよう.これは4GBに相当する.開発機なら走るが,他のマシンでは無理だ.1GBというのがほどほどというところではないだろうか?つまり,1,073,741,824だ.
Max numberでは巨大数を表示できているのに,Max node countやvoid node countでは表示できないのはなぜだろう?MaxLengthは32767で同じだ.height=11111でMAXは5302文字になる.height=111111では32767を軽く超えてしまうのだろう.MaxLengthを少し増やしてみよう.MaxNumber.textには値が入っているのに表示されていない.テキストは53051文字で32767を超えている.どうも,これが仕様なのではないかと思う.テキストボックスの幅を広げてみたが同じだ.ただし,値はBigIntegerとして保持されているので計算を進めることはできる.
▲リリース版でTree heightに大きな数字を入れたらハングしてしまった.開発環境でも起きる.H=1111111のとき,BigInteger.Powの内部でハングしている.これはこの関数の限界に達したことを意味している.メモリの問題かもしれないが,例外は発生しない.⇒この関数の第2引数はInt32なのでその上限を超えているということだろう.枝数と高さは整数範囲に押さえておいた方がよい.
大体収まったのではないかと思う.枝数と高さを変えたときには,無条件で停止するようにした.枝数と高さはマニュアルでは長整数の範囲としているが,Int16の範囲内に留めることにした.この程度が現実的に見て妥当なところではないか思う.一応これで差し替え版はできたのではないかと思う.枝数3,高さ1000というサンプルを走らせてみよう.⇒2時間走っているが,問題なさそうだ.数字が大きくなるとダンプの1行が長くなり,ほとんど画面に1行しか表示されないようになる.ワードラップが切り替えられるようにできるとよい.
▲タブAが走っているとき,タブBのOdd numberに巨大数を入力→Get the Sequenceのあと,Wordwrapを操作しながらTruncated treeを実行してだんまりになってしまった.また,Get the sequenceでスクロールは続いているが,表示も遅く,degreeやheightがまったく更新されない.⇒ループ内で表示を更新し,DoEventsで再描画するようにした.
▲Verificationを中断したときにも,送信ボタンが出ているのはよいが,検定にパスしたように見えてしまうのではないか?途中で打ち切っても検定成功!が出ている.⇒対処した.
▲B面は他のボタンを押したとき反応がない.Stopボタン表示もない.VerifyにはStopがあるが,他の3つの処理は停止できない.対象が巨大数の場合など,打ち切りが必要な場合がある.Wordwrapの切り替えも入らない.いま,どの処理をやっているのかも分からない.Stopは表示しなくても,二度押しで一度停止するようにした方がよい.⇒対処した.
▲Get the sequenceで初期化→更新していない.⇒対処した.
▲Verificationで3から開始して,ODD<>ODD2で停止した.GetTheNumberの中でOddNumber.textを書き換えている.⇒上記で修正ミス(フラグ操作の落ち)があった.