4

リストをループし、cfhttp を介して一連の SOAP 呼び出しを行う cfc メソッドがあります。次に、結果をデータベースに挿入します。

プロセス自体はうまく機能します。問題は、Java メモリがゆっくりといっぱいになり、最終的には (返されるレコード内の要素の数に応じて) 動作を停止することです。エラーや目に見えるものはなく、停止するだけです。coldfusion admin 経由でアプリケーション ログ ファイルを見ると、次のエラーのいずれかまたは両方が表示されます。

GC overhead limit exceeded The specific sequence of files included or processed is:

また

Java heap space The specific sequence of files included or processed is:

以下は、私が実行しているコードの簡略版です。

<cfsetting requesttimeout="3600">
<cfloop condition="thisPass lt 10">
    <cfscript>
        runtime = CreateObject("java","java.lang.Runtime").getRuntime();
        objSystem = CreateObject( "java", "java.lang.System" );
        soapBody = '';
        soapResponse = '';
        thisStruct = '';
        lock scope='application' type='exclusive' timeout='60' {


//This is where I am trying to manage the memory and call garbage collection


        try {
            freeMemory = runtime.freeMemory()/1024/1024;
            writeOutput("- fm = "&freeMemory);
            if (freeMemory < 200){
                objSystem.gc();
                sleep(1000);
                writeDump(' - dumping freeMemory');
             }
         }
         catch(any error) {
            writeDump(' - trying to dump GC as '&now()& ' freeMemory = '&freeMemory);
         }
         }
        </cfscript>
        <cfsavecontent variable="soapBody">
            <?xml version="1.0" encoding="utf-8"?>
            [ BUILD SOAP ENVELOP ]
        </cfsavecontent>

        <cfhttp url="[URL]" method="post" result="httpResponse" 
                        timeout="600" resolveurl="false">
                <cfhttpparam type="header" name="SOAPAction" value="[URL2]" />
                <cfhttpparam type="xml" value="#trim( soapBody )#"/>
            </cfhttp>


            <cfscript>
                soapBody = "";
                soapResponse = httpResponse.fileContent;
                soapResponse = xmlParse( soapResponse );
                thisStruct = xmlSearch(soapResponse,'/soap:Envelope/soap:Body/')[1].xmlChildren[1].xmlChildren[1].xmlChildren;
                writeOutput("-"&arrayLen(thisStruct)&' records');
                getPageContext().getOut().flush();
                if(arrayLen(thisStruct) == 2500){
                    thisPass = thisPass+1;
                } else {
                    writeOutput("- total records = "&(2500*(thisPass-1))+arrayLen(thisStruct));
                    thisPass = 100; // since looping while thisPass lt 10 this should prevent the next iteration
                }
            </cfscript>

            <cfloop from="1" to="#arrayLen(thisStruct)#" index="i">
                [RUN PROC TO INSERT RECORDS]
            </cfloop>
        </cfloop>

GC は時々メモリを少し解放するようですが、信頼性はありません。GC() は、Java が未使用のメモリの一部を解放するための推奨事項にすぎないことを理解していますが、強制的にメモリを解放する方法がわかりません。どこかで漏れている可能性がありますが、私はそれを見ていません。私はこれが私が見過ごした明らかなものであることを望んでおり、私の Java の知識は非常に限られていることを認めます。

私のエラーを見ることができるJavaの第一人者はいますか?

更新:これは、メモリの減少を確認するのに役立つ場合の出力のサンプルです。

ループするリストは 236 個あります

  1. 88185 - fm = 293.564407349 -6 レコード - 合計レコード = 6
  2. 88389 - fm = 290.86995697 -116 レコード - 合計レコード = 116
  3. 88390 - fm = 308.382568359 -262 レコード - 合計レコード = 262
  4. 88839 - fm = 292.707099915 -2032 レコード - 合計レコード = 2032
  5. 91088 - fm = 290.711753845 -6 レコード - 合計レコード = 6
  6. 92998 - fm = 287.754066467 -5 レコード - 合計レコード = 5
  7. 95510 - fm = 309.919425964 -91 レコード - 合計レコード = 91
  8. 96478 - fm = 292.035064697 -1180 レコード - 合計レコード = 1180
  9. 96479 - fm = 259.001213074 -1113 レコード - 合計レコード = 1113
  10. 96480 - fm = 261.121406555 -110 レコード - 合計レコード = 110
  11. 96796 - fm = 267.235244751 -2 レコード - 合計レコード = 2
  12. 96799 - fm = 265.037582397 -0 レコード - 合計レコード = 0
  13. 97435 - fm = 263.589103699 -2500 レコード - fm = 227.629760742 -2500 レコード - fm = 200.85987854 -2500 レコード - fm = 202.156776428 -2500 レコード - fm = 166.366210938 - フリーメモリのダンプ -6 合計 60 レコード = 65
  14. 98173 - fm = 160.579734802 - freeMemory のダンプ -35 レコード - 合計レコード = 35
  15. 99111 - fm = 176.218482971 - freeMemory のダンプ -0 レコード - 合計レコード = 0
  16. 100998 - fm = 194.708694458 - freeMemory のダンプ -185 レコード - 合計レコード = 185
  17. 101811 - fm = 160.61415863 - freeMemory -2500 レコードのダンプ - fm = 112.862670898 - freeMemory -2500 レコードのダンプ - fm = 86.2071380615 - freeMemory -2500 レコードのダンプ - fm = 52.9639358521 - freeMemory -1064 レコードのダンプ - 合計 4 レコード = 85
  18. 105014 - fm = 56.1721343994 - freeMemory のダンプ -14 レコード - 合計レコード = 14
  19. 105992 - fm = 73.0022964478 - freeMemory のダンプ -14 レコード - 合計レコード = 14
  20. 107539 - fm = 75.9522399902 - freeMemory のダンプ -93 レコード - 合計レコード = 93
  21. 107580 - fm = 58.345199585 - freeMemory のダンプ -2500 レコード
4

4 に答える 4

1

多くの検索を行った結果、この特定の問題に対する最善の「修正」は、ガベージコレクションを実行しようとしていたコードを削除し、Javaヒープサイズを増やすことであることがわかりました。/jrun/bin/jvm.configファイル内。

VMへの引数を次のように変更します。

java.args=-server -Xms2048m -Xmx2048m -Xmn1024m -Dsun.io.useCanonCaches=false -XX:MaxPermSize=192m -XX:+UseParallelGC -Xbatch -Dcoldfusion.rootDir={application.home}/ -Djava.security.policy={application.home}/servers/cfusion/cfusion-ear/cfusion-war/WEB-INF/cfusion/lib/coldfusion.policy -Djava.security.auth.policy={application.home}/servers/cfusion/cfusion-ear/cfusion-war/WEB-INF/cfusion/lib/neo_jaas.policy

初期ヒープサイズ(Xms)と最大ヒープサイズ(Xmx)を2048mに、「若い世代」のヒープサイズ(Xmn)を1024mに増やすことができました。より良いガベージコレクションのための初期値と最大値よりも。

Jamesが提案したように、私は実際のプロセス(関数内にあり、var'd)をコメントアウトしてから、コメントを外して、毎回すべてを実行します。これによって私が学んだことは、大きなSOAP応答はメモリをいっぱいにしているものであり、私が恐れていたようなリークではないということでした。

Adamが述べたように、それはJavaによるGCの管理ではなく、管理するための十分なスペースがありませんでした(何らかの理由で、CFは2500レコードのSOAP応答をうまく処理するのが好きではありません)。形。

アダムはまた、CFでのJavaメモリのトラブルシューティングは「ダークアート」であると言って正しかった。サーバーモニターを使用してhttp://localhost/CFIDE/administrator/monitor/launch-monitor.cfm、[メモリ使用量]-> [メモリ使用量の概要]の下の統計タブに移動すると、メモリがゆっくりといっぱいになり、自分自身をダンプするのを見ることができました。新たに再起動した後、実行中のプロセスはありません。理由を理解することはできませんでしたが、どのレベルが実行されているか、そして私がトップに到達していることはわかりました。

jvm.configファイルに割り当てられたデフォルトのメモリは512mであり、何が起こっているかを処理するには単に十分ではありませんでした。この全体的なプロセスを処理するためのより良い方法があるかもしれません。ヘンリーの提案を実装してデータベースに入れ、それをチャンクする必要があるかもしれませんが、それは私には非常に不器用に聞こえます。

CFがゲートからすぐに大量のリソースを使用していることを除けば、このソリューションには他の問題がある可能性がありますが、(今のところ)必要に応じて機能しているようです。

更新: cfc関数を変更して、すべてをデータベースに挿入する代わりに、すべてのXMLをファイルに書き込んでから、ファイルを読み取ってデータベースに挿入するようにしました。どういうわけか、ファイルへの書き込みにより、JavaはGC()自体を実行するのに十分な時間「呼吸」することができました。

于 2013-02-08T22:18:42.500 に答える
1

フォース GC のアプローチは、試してみてもあまり役に立たなかったと言えます。一般的に、最初に試すことのリストを次に示します。

  • 変数を呼び出しているオブジェクトで var または local を使用していることを確認してください
  • 処理をデータベースに移動できる場合は、そうしてください
  • 取り外し<cfdump><cfdump>非常に重いです。本当に使用する必要がある場合は、変数の必要な部分だけに注目してください。テキスト形式も使用
  • JVM を変更してより多くのメモリを使用する
  • Java 1.7 および G1GC を使用します。(まだサポートされていない可能性があるため、注意してください)
  • 使用するクエリのクエリ数を減らす

上記のコードについて私が検討するもののリストは次のとおりです

  • look 内のすべてを関数と var スコープに移動します。
  • thisStuct を使い終わったら、StructClear(thisStruct);
  • writedump();のように重い彼らの領域の書き込みを取得します<cfdump>
于 2013-02-08T17:20:25.107 に答える
1

Java が GC をうまく管理していないということではありません。ガベージ コレクターがクリーンアップできるように、メモリに入れているもの (およびメモリから取り出しているもの) を管理していない場合です。 . あなたはここの問題ではなく症状を(~しようとして)治療しています。

メモリに何が入っているのか、GC されると予想されるものがなぜ GCされないのかを調べてください。共有スコープ内のものへの参照を (予期せずに) 持っているか、そのようなものである可能性があります。ただし、Java 上で ColdFusion を使用してこの種のトラブルシューティングを行うのは、少し暗い芸術です。

ただし、GC を強制したときに GC されないという「問題」を「修正」しようとしないでください。メモリがいっぱいになる原因となっている問題を修正してください。b) GC 対応であるべきだと思うときに、GC 対応にしないこと。

于 2013-02-08T17:16:13.423 に答える
0

AFAIK CFは長いリクエストを実行するのが苦手です。私が聞いたところによると、リクエストが完了するまでメモリは解放されません。

私たちが試したのは、長いリクエストを CF が管理できる小さなリクエストに分割することでした。通常、メモリはリクエストが完了すると解放されます。

私たちが使用する 1 つのレガシー システムは、タスクを DB テーブルに挿入し、CF スケジューラは一度にバッチで動作します。遅延のせいでそれが嫌だったのですが、それは CF7 の時代に必要だったもので、それ以来改善されていないようです.

于 2013-02-08T19:07:44.380 に答える