2009-10-26 10 views
9

私は負荷テストをしようとしているサーバーコンポーネントを持っています。サーバーへのすべての接続はTLS 1.0を使用します。私は私が欲しいと本質的に多くのスレッドでこれを行う簡単なテストプログラムを持って次のようにSunのJava SSL実装でメモリがリークしていますか?

Full TLS handshake to the server 
send a request 
read reply 
close connection 
repeat ad nauseam 

私の仮想マシンは、次のとおりです。

Java(TM) SE Runtime Environment (build 1.6.0_16-b01) 
Java HotSpot(TM) Server VM (build 14.2-b01, mixed mode) 

私はメモリリークを持っています。サーバーを頻繁にテストすると、メモリのフットプリントが約1メガバイト増加し、OutOfMemoryExceptionで15〜20分後にブロックされます。

Netbeanのプロファイラで実行したところ、TLS API内でメモリの増加が深刻であることがわかりました。

似たような経験をしたことがありますか?自分のレベルで実装できる回避策はありますか?

編集。要求されたとして、ここではこれらのバイトの多くを生成し、プロファイリングコール・トレースは[]です:

.java.io.ByteArrayOutputStream.<init>(int) 
..com.sun.net.ssl.internal.ssl.OutputRecord.<init>(byte, int) 
...com.sun.net.ssl.internal.ssl.OutputRecord.<init>(byte) 
....com.sun.net.ssl.internal.ssl.AppOutputStream.<init>(com.sun.net.ssl.internal.ssl.SSLSocketImpl) 
.....com.sun.net.ssl.internal.ssl.SSLSocketImpl.init(com.sun.net.ssl.internal.ssl.SSLContextImpl, boolean) 
......com.sun.net.ssl.internal.ssl.SSLSocketImpl.<init>(com.sun.net.ssl.internal.ssl.SSLContextImpl, java.net.Socket, String, int, boolean) 
.......com.sun.net.ssl.internal.ssl.SSLSocketFactoryImpl.createSocket(java.net.Socket, String, int, boolean) 
<my code> 

私は置くことができ、より多くのは、これは長いだろう...があります。プロファイラは、私を与えることを私はあなたのエントリポイントを教えてあげる:

....com.sun.net.ssl.internal.ssl.AppOutputStream.<init>(com.sun.net.ssl.internal.ssl.SSLSocketImpl) 
....com.sun.net.ssl.internal.ssl.HandshakeOutStream.<init>(com.sun.net.ssl.internal.ssl.ProtocolVersion, com.sun.net.ssl.internal.ssl.ProtocolVersion, com.sun.net.ssl.internal.ssl.HandshakeHash, com.sun.net.ssl.internal.ssl.SSLSocketImpl) 
....com.sun.net.ssl.internal.ssl.SSLSocketImpl.sendAlert(byte, byte) 
..com.sun.net.ssl.internal.ssl.AppInputStream.<init>(com.sun.net.ssl.internal.ssl.SSLSocketImpl) 
..com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake() 
..com.sun.net.ssl.internal.ssl.HandshakeInStream.<init>(com.sun.net.ssl.internal.ssl.HandshakeHash) 
+2

より具体的なプロファイリング結果を提供できますか?リークは必ずしもTLSのものではなく、あなたのコード内にある可能性があります。 –

+1

この動作を示す最小限のプログラムを作成し、質問に追加してください。 –

答えて

4

接続が近くに見えました。おそらくこれは何とか開いている可能性が高いです。 1Mbは余分なスレッドを歌います。しかし、私は正確に何が原因だろうか分かりません。

+0

私はそれを見ました。私は 'Executors.newScheduledThreadPool'を使用していますので、いつでも実行されているスレッドの数を完全に制御することはできません。つまり、プロファイラの結果は、ほとんどのメモリがbyte []に​​よって占められていることを示しています。 – malaverdiere

+0

クライアントの切断が正しく処理され、接続が閉じられたことを再確認します。良いアイデア。 – malaverdiere

+0

うん、それは大きな違いを作った! (IOExceptionをキャッチすることによって)切断が検出されたにもかかわらず、私はSSLSocketをクローズしていませんでした。 – malaverdiere

8

すべてのSSL接続が後の一時的な暗号化キーのネゴシエーション時のハンドシェイクのオーバーヘッドを削減するために個別のTCP接続で再利用することができるSSLセッションに関連付けられています実際のTCP接続が確立されています。クライアントが何らかの形で新しいセッションの作成を強制している可能性があります。また、Java 6のデフォルト設定ではセッションを無制限に1時間キャッシュするように見えますので、簡単にメモリの問題に遭遇する可能性があります。

getSession()。getSessionContext()を使用してSSLSessionContextをサーバーソケットから取得し、setSessionTimeoutを使用してsetSessionCacheSizeおよびtimeout(秒)でキャッシュサイズを設定することにより、サーバーソケットのこれらの設定を操作できます。私はそれがシステムのプロパティを介してデフォルトの設定を変更することが可能になると思っていただろうが、私はそれに関するドキュメントを見つけることができません。おそらく、あなたは私がやったよりも少しだけグーグルで何かを見つけることができます。


正しいセッションコンテキストに制限を設定してもよろしいですか?私は、サーバーソケットから到達可能なコンテキストに間違いがありました。あなたはサーバソケットを作成する前にするSSLContextを通してそれを設定する必要があります。この制限がないと

SSLContext sslContext = SSLContext.getDefault(); 
sslContext.getServerSessionContext().setSessionCacheSize(1000); 
SSLServerSocket ss = (SSLServerSocket) 
    sslContext.getServerSocketFactory().createServerSocket(<port>); 

を各キャッシュされたSSLセッションの継ぎ目が7から800バイトの周りのどこかで使用するよう、あなたのメモリ「リーク」を再現するのは簡単でしたヒープメモリセッション数の制限により、私のサーバーは約15分間ストレス下で稼動しており、まだ3-4 MBのヒープメモリしか使用していません。

+0

私は1000セッションの制限を設定しました。クラッシュ前のカーブは以前と同じように急ではありません(今は階段のように見えます)ので、これは助けになります。 それでも、それはまだクラッシュします。 – malaverdiere

+0

投稿編集で提案したコードスニペットを試しましたか? – jarnbjo

+2

デフォルトのタイムアウト(24時間)は86400secで、デフォルトのキャッシュサイズは次のように設定できます。w/'-Djavax.net.ssl.sessionCacheSize = xxx'プロパティ – bestsss

1

1MBは、スレッドを作成するために必要なメモリです(余分かどうか)。

そのクラスまたはパッケージのバグリストにエントリがありますか?最初のステップはそれを確認することです。

第2のステップは、サンのものではなくコードに問題があると想定することです。 Java JDKの一般的に使用されているクラスが、世界中のユーザーによって叩かれているからです。間違いがあった場合、これまでには明るくなっていたでしょう。

これは、JDKコードがバグフリーであると言うわけではありません。コードを最初に疑う必要があるということだけです。

プロファイラと測定を取得します。推測しないでください。

+1

+1 - あなた自身のコードを最初に疑います。 –

+0

私が言ったように、私はプロファイラで実行しました。すべてのオーバーヘッドは、SSL実装内で深く作成されたbyte []に​​よるものです。 – malaverdiere

0

どのハードウェアを実行していますか? netstatを実行して接続の状態を確認できますか?

私はTomcatを負荷テストしたが、Solarisで1GBのヒープで何時間も実行しても500回の新しいSSL要求/秒を達成できた。また、コンテナ内で実行されているスレッドの数を監視することもできます。

関連する問題