3

.NET 3.5 を使用しています。

X509Certificate への参照を作成するときにメモリ リークが発生します。結果を分析するために ANTS プロファイラーを使用していますが、プライベート バイトが増加している一方で、ヒープ内のバイトは静的なままです (アンマネージ コードによるメモリ リークであることを示しています)。

CRYPT32 dll を使用して証明書を管理しています。内部ポインター (intptr) であるストア ハンドルを取得するために、証明書ストアへの参照を開きます。次に、このストア ハンドラーを使用して、ストア (ローカルに保存) 内の証明書を検索します。証明書を取得したら、証明書ストアを閉じて、証明書を呼び出し元のプログラムに返します。クローズストアが呼び出された後、開いているリソースを開いたままにする certclosestore でフラグ 0 を使用しています。ここで言及されているように、これがメモリリークの原因であると思います: http://msdn.microsoft.com/en-us/library/ms937035.aspx

ただし、閉じるフラグを次のように変更すると:

CertCloseStore(storeHandle, 2)

これにより、割り当てられたリソースが解放されるはずです。ただし、サービスが爆破されるだけです。

アプリケーションは、証明書などを検証するという意味で機能します。唯一の問題は、メモリ使用量が徐々に増加し、サービスを毎週かそこらで再起動する必要があることです。どんなアイデアや考えでも大歓迎です。

public static X509Certificate CreateFromRegistry(string certificateIdent)
{
  X509Certificate certificate = null;
  IntPtr storeHandle = CertificateStore.CertOpenStore(CERT_STORE_PROV_SYSTEM, 
      0, 0,CERT_SYSTEM_STORE_LOCAL_MACHINE, "MY");;

  certificate = new X509Certificate(CertificateStore.
  FindCertInStore(certificateIdent, storeHandle));
  CertificateStore.CertCloseStore(storeHandle, 0);
  return certificate;
}



public class CertificateStore
{
    const int CERT_STORE_PROV_SYSTEM = 10;
    private static int CERT_SYSTEM_STORE_LOCAL_MACHINE = (2 << 16);
    const uint PKCS_7_ASN_ENCODING = 0x00010000;
    const uint X509_ASN_ENCODING = 0x00000001;
    const uint CERT_FIND_SUBJECT_STR = 0x00080007;
    const uint CERT_FIND_ISSUER_STR = 0x00080004;
    static uint MY_ENCODING_TYPE = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;

    [DllImport("CRYPT32", EntryPoint = "CertOpenStore",
        CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern IntPtr CertOpenStore(
        int storeProvider, int encodingType,
        int hcryptProv, int flags, string pvPara);

    [DllImport("CRYPT32", EntryPoint = "CertCloseStore",
        CharSet = CharSet.Unicode, SetLastError = true)]
    public static extern bool CertCloseStore(
        IntPtr storeProvider,
        int flags);
}

public static X509Certificate FindCertInStore
        (string trustedRootIssuerName, IntPtr storeHandle)
    {
        IntPtr hCertCntxt;
        X509Certificate theActualCertificate = null;

        if (storeHandle != IntPtr.Zero)
        {
            hCertCntxt = CertFindCertificateInStore(
               storeHandle,
               MY_ENCODING_TYPE,
               0,
               CERT_FIND_ISSUER_STR,
               trustedRootIssuerName,
               IntPtr.Zero);

            if (hCertCntxt != IntPtr.Zero)
            {
                theActualCertificate = new X509Certificate(hCertCntxt);
            }
        }
        return theActualCertificate;
    }
4

1 に答える 1

3

もちろん、CRYPT32 リソースをリークしています。あなたのスニペットですぐにわかる候補の 1 つは、CertFindCertificateInStore() の戻り値です。CertFreeCertificateContext() への明示的な呼び出しによって解放する必要がありますが、私にはわかりません。

X509Certification(IntPtr) コンストラクターは十分に文書化されておらず、コンテキストが有効である必要がある期間について説明していません。X509Utils._DuplicateCertContext() という名前の内部メソッドを呼び出していることがわかります。非常に高い確率で、オブジェクトを作成した後すぐに release 関数を呼び出すことができます。

CRYPT32 から取得したすべてのハンドルとポインターが解放されていることを、細かいコームとトリプル チェックでコードの残りの部分をチェックしてください。

于 2012-08-16T12:37:03.997 に答える