2

autocreateDatastoreTxns の設定によっては、メモリ リークが発生し、以下の各クラスの 1 つのインスタンスがクエリ (読み取り) ごとに作成されます。つまり、100 個のクエリは、以下の各クラスの 100 個のインスタンスを作成します (クエリごとに 2 つのインスタンスを取得する DatastoreServiceConfig を除く)。

これは、開発環境で Java VisualVM プロファイラーを使用して見つけました。私がこれを行っている理由は、本番環境では、インスタンスのヒープ サイズが増加し続け (通常、1 万から 2 万のリクエスト後に大きくなりすぎ)、最終的に応答が遅くなり、インスタンスの再起動が発生するためです。これが原因かはわかりませんが、ここまで特定できたリークは初めてです。

// datanucleus.appengine.autoCreateDatastoreTxns=false でリークします

org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManager
org.datanucleus.store.appengine.KeyRegistry
org.datanucleus.store.appengine.EmualtedXARResource
org.datanucleus.store.appengine.DatastoreConnectionFactoryImpl$DatastoreManagedConnection

// datanucleus.appengine.autoCreateDatastoreTxns=true でリークします

com.google.appengine.api.datastore.DatastoreServiceConfig  // 2 instances per query
org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManager
com.google.appengine.api.datastore.AsyncDatastoreServiceImpl
com.google.appengine.api.datastore.DatastoreServiceImpl
org.datanucleus.store.appengine.jdo. DatastoreJDOTransation
com.google.appengine.api.datastore.DatastoreXARResource
com.google.appengine.api.datastore.DatastoreProperty
com.google.appengine.api.datastore.KeyRegistry
com.google.appengine.api.datastore.DatastoreConnectionFactoryImpl$DatastoreManagedConnection
com.google.appengine.api.datastore.TransactionStackImpl$ThreadLocalTransactionStack$StaticMember
com.google.appengine.api.datastore.TransactionStackImpl
org.datanucleus.store.appengine.RuntimeExceptionWrapperingDatastoreService

これが私のコードです:

PersistenceManager pm = PMF.get().getPersistenceManager();
try {
    account = pm.detachCopy(pm.getObjectById(Account.class, accountKey));
} catch (javax.jdo.JDOObjectNotFoundException ex) {
    account = null;
} finally {
    pm.close();
}

アイデア/考えはありますか?これは Google AppEngine の本当のメモリ リークですか、それとも開発環境の単なる事実ですか、それとも私自身のエラーでしょうか?

4

3 に答える 3

1

開発アプリケーションサーバーは、実際のアプリケーションサーバーのセマンティクスをシミュレートすることを目的としているため、妥当な忠実度で開発できます。これには、特にデータストアに関するメモリの動作は含まれません。開発サーバーは、実際のアプリケーションサーバーが保持しない方法で物事をメモリに保持する傾向があります。開発サーバーのプロファイリングは、アプリ側のリークを整理するのに引き続き役立ちますが、アプリサーバー側にある可能性のあるリークについてはあまりガイダンスを提供しません. ただし、それらには注意してください。そして、ヒープは時間の経過とともに断片化します。

一部のアプリは、使用方法とデータ アクセス パターンの性質上、より大きなフロントエンド インスタンスの恩恵を受けます。それらはより多くのコストがかかるため、追加コストに対する利点をテストして重み付けする必要があります.

于 2012-09-08T03:47:03.950 に答える
1

私が見たところ、実稼働の AppEngine で JDO メモリ リークが発生しています。

これにより、時間の経過とともにインスタンスのレイテンシが増加します。この問題はしばらく前から存在しており、明確な解決策が公式に提供されていません。そのため、以下は、私が本番システムで 1 年以上使用してきた PMF クラスの簡単な解決策であり、遅延の増加の問題を解決しました (メモリ使用量は増加しますが、それほど速くはありません)。

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

public final class PMF {

    private static final int RECYCLE_POINT = 5000;
    private static final int BUFFER_ZONE = RECYCLE_POINT / 10;
    private static int pmfcount = 1;
    private static int marker = Integer.MIN_VALUE;
    private static PersistenceManagerFactory pmfInstancePrevious = null;
    private static PersistenceManagerFactory pmfInstance = JDOHelper
            .getPersistenceManagerFactory("transactions-optional");

    private PMF() {
    }

    public static PersistenceManagerFactory get() {
        int icount = pmfcount;
        if (icount % RECYCLE_POINT == 0) {
            synchronized (pmfInstance) {
                pmfInstancePrevious = pmfInstance;
                marker = icount;
                pmfInstance = JDOHelper
                    .getPersistenceManagerFactory("transactions-optional");
            }
        }
        if(marker+BUFFER_ZONE == icount) {
            if (null != pmfInstancePrevious) pmfInstancePrevious.close();
        }
        pmfcount++;
        return pmfInstance;
    }
}

コードはスレッド セーフ (同期) であり、マルチスレッド インスタンスで使用でき、JDO コードに他の変更を加える必要はありません。

PMF.get() の使用状況に応じて RECYCLE_POINT を微調整できますが、5000 回の呼び出しが新しいインスタンスを取得するのに適していることがわかりました。

BUFFER_ZONE は、使用中に PMF が閉じられたというメッセージが表示される場合にも重要です。これは、PersistenceManagerFactory の周りにハンドルを保持しているか、非常に長い期間のリクエストを行っていることを意味します。代わりに、リクエストの開始ごとに (または各リクエストで複数回) PMF.get() を使用する必要があります。以前の PMF インスタンスをより長く維持したい場合は、BUFFER_ZONE を増やしますが、常に RECYCLE_POINT の一部です。

于 2014-05-07T13:29:54.407 に答える
0

GAEリークの可能性があります。コードのバグである可能性もあります。ケースを区別する唯一の方法は、(考えられる) リークの実際の原因を追跡することです。

リークがコードの別の部分にある可能性があることを付け加えておきます。たとえば、永続マネージャを別の場所で使用している場合。FWIW、あなたの質問のコードは私には問題ないようです...

于 2012-09-08T02:52:35.087 に答える