none
MM_ISOTROPICでフォント描画するとメモリリークします RRS feed

  • 質問

  • VisualStudio2005 VC++(MFC)でアプリ開発しています。

    下部に記載したのは,マッピングモードMM_ISOTROPICでビューポートを変更して,

    ズーム倍率を任意に変更し,拡大縮小を行っている単純な処理なのですが

    MM_ISOTROPICでフォント描画し,拡大縮小を繰り返すとメモリリークします。

     

    http://support.microsoft.com/kb/149289/ja

    に類似したバグレポートあるようなのですが,

    どなたか本件の解決方法ご存じではないでしょうか?

     

    -------------------------------以下,サンプルソース--------------------------------------
    void CtestpView:SurprisenDraw(CDC* pDC)
    {
     CtestpDoc* pDoc = GetDocument();
     ASSERT_VALID(pDoc);
     if (!pDoc)
      return;

     // TODO: この場所にネイティブ データ用の描画コードを追加します。

     


     CString fname ;

     fname = _TEXT("MS ゴシック") ;

     m_Font_Wk.CreateFont(
      30, 0, 0, 0,
      FW_NORMAL,
      FALSE,
      FALSE,
      0,
      SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
      DEFAULT_QUALITY, FIXED_PITCH|FF_MODERN,
      fname );

     


     // フォント
     m_pOldFont = pDC->SelectObject(&m_Font_Wk) ;         // ローカルフォント

     
     for(int i = 0; i<=10000; i=i+30){
      // pDC->TextOut(i,i, TEXT("ABCDEGHIJKLMNOPQRSTUVWXYZ"));    // 半角文字
      pDC->TextOut(i,i, TEXT("ABCEFGHIJKLMNOPQR")); // 全角文字
     }


      // GDIオブジェクトの復元
     pDC->SelectObject(m_pOldFont) ; 


     m_Font_Wk.DeleteObject();
    }


    // CtestpView メッセージ ハンドラ

    void CtestpView:SurprisenPrepareDC(CDC* pDC, CPrintInfo* pInfo)
    {
     // TODO: ここに特定なコードを追加するか、もしくは基本クラスを呼び出してください。

     // マッピングモード  対称任意設定
     pDC->SetMapMode(MM_ISOTROPIC);
     //pDC->SetMapMode(MM_TEXT);
     // デバイス コンテキストに関連するウィンドウの x 範囲と y 範囲を設定 (論理単位)
     pDC->SetWindowExt(m_nLogi_Area_Size.cx, m_nLogi_Area_Size.cy);
     // デバイス コンテキストのビューポートの x 範囲と y 範囲を設定 (デバイス単位)
     pDC->SetViewportExt(int(m_nLogi_Area_Size.cx * m_zoom/ZOOM_BASE), int(m_nLogi_Area_Size.cy * m_zoom/ZOOM_BASE));

     // 背景色透過モード設定
     pDC->SetBkMode(TRANSPARENT) ;
     // 円弧描画右回り
     pDC->SetArcDirection(AD_CLOCKWISE) ;
     //  テキストアライン
     //  TextOutで指定する座標が、出力するテキストの左下隅になるように設定します。
     pDC->SetTextAlign(TA_LEFT | TA_BOTTOM) ;


     CView:SurprisenPrepareDC(pDC, pInfo);
    }

    void CtestpView:SurprisenLButtonDown(UINT nFlags, CPoint point)
    {
     // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。

     m_zoom += 10 ;

     Invalidate(TRUE) ;

     CView:SurprisenLButtonDown(nFlags, point);
    }

    void CtestpView:SurprisenRButtonDown(UINT nFlags, CPoint point)
    {
     // TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。

     m_zoom -= 10 ;

     Invalidate(TRUE) ;

     CView:SurprisenRButtonDown(nFlags, point);
    }

     

     

    2008年7月1日 8:52

回答

  •  r-takaha さんからの引用
    >私なら MM_ISOTROPIC の使用を避けるという方法で逃げてしまうと思います。

     →私は,論理座標に描画した図形や文字を拡大縮小して表示する手段として,MM_ISOTROPICのマッピングモード

      を指定して,SetViewportExtで表示したいサイズを指定する方法しか知らないのですが,

      別の良い方法があるのでしょうか?


    MM_ISOTROPIC (あるいは MM_ANISOTROPIC) が一番簡単で、便利な方法だと思います。


    私が考える「逃げ」は、もっと泥臭い方法でして、論理座標→デバイス座標の変換をゴリゴリ自前でやってしまうというものです。

    ただ、座標変換とはいっても、本当にやりたいことは単なる拡大縮小なので、原点からの距離に係数をかけるだけの単純なものになると思います。

    問題はフォントですが、これは拡大率が変わったときに拡大率に応じた大きさのフォントを毎回作り直さなければなりません。

    (MM_ISOTROPIC モードでは、SetViewportExt がこの処理を担当しているはずです。そして、コイツが前回のフォントを開放してくれないので、使用メモリがどんどん増えていくのではないかと思われます。)


    期待はずれの方法かも知れませんが、他に方法がなければこういった逃げの手も一考に値するのではないでしょうか。


    2008年7月2日 1:40

すべての返信

  • ちょっと試してみたのですが、私が試した限りでは、メモリリークというよりは一回作ったものを開放していないような動作に見えるのですが、同じ現象でしょうか?

    タスクマネージャで仮想メモリサイズを眺めていると、一度でも表示したことのあるフォントサイズの場合は仮想メモリサイズに変化がなく、
    いままでに表示したことのないサイズを表示する段階で仮想メモリサイズが増加していました。

    例えば、「拡大・拡大・拡大・縮小・縮小・縮小」という操作だと、拡大のときは仮想メモリサイズが増加し、縮小のときは変化しません。
    ここで更に「縮小」とすると、仮想メモリが増加します。

    メモリリークというと拡大・縮小・拡大・縮小…と繰り返していると無限にメモリを消費するようなイメージですが、
    この場合はいつまでも開放しないだけで、一度作ったことは覚えているようです。
    メモリリークというよりは行儀の悪いメモリプールといったところでしょうか。

    とはいえ、半角の場合は仮想メモリサイズが変化しませんので、
    何か良からぬことが起きていることだけは間違いないようです。

    バグでしょうかね?
    私なら MM_ISOTROPIC の使用を避けるという方法で逃げてしまうと思います。

    2008年7月1日 12:06
  • ご助言ありがとうございました。 まさしく記述頂いている通りの現象です。

    一度表示したサイズのフォントを再描画する場合には仮想メモリは増えません。 また全角文字はメモリリークの様な現象が発生しますが,全く同じ処理でも半角テキストの表示ではメモリは増えません。

    ただ,このメモリが増えるのが有限であれば良いのですが,テストしたところ無段階に拡大縮小を繰り返し続けると,やがてメモリ不足となって,全角文字が表示されなくなります!! 非常に困っています。

     

    >私なら MM_ISOTROPIC の使用を避けるという方法で逃げてしまうと思います。

     →私は,論理座標に描画した図形や文字を拡大縮小して表示する手段として,MM_ISOTROPICのマッピングモード

      を指定して,SetViewportExtで表示したいサイズを指定する方法しか知らないのですが,

      別の良い方法があるのでしょうか?

      有識者の方,御教示頂けますようお願い致します。

    2008年7月2日 0:19
  •  r-takaha さんからの引用
    >私なら MM_ISOTROPIC の使用を避けるという方法で逃げてしまうと思います。

     →私は,論理座標に描画した図形や文字を拡大縮小して表示する手段として,MM_ISOTROPICのマッピングモード

      を指定して,SetViewportExtで表示したいサイズを指定する方法しか知らないのですが,

      別の良い方法があるのでしょうか?


    MM_ISOTROPIC (あるいは MM_ANISOTROPIC) が一番簡単で、便利な方法だと思います。


    私が考える「逃げ」は、もっと泥臭い方法でして、論理座標→デバイス座標の変換をゴリゴリ自前でやってしまうというものです。

    ただ、座標変換とはいっても、本当にやりたいことは単なる拡大縮小なので、原点からの距離に係数をかけるだけの単純なものになると思います。

    問題はフォントですが、これは拡大率が変わったときに拡大率に応じた大きさのフォントを毎回作り直さなければなりません。

    (MM_ISOTROPIC モードでは、SetViewportExt がこの処理を担当しているはずです。そして、コイツが前回のフォントを開放してくれないので、使用メモリがどんどん増えていくのではないかと思われます。)


    期待はずれの方法かも知れませんが、他に方法がなければこういった逃げの手も一考に値するのではないでしょうか。


    2008年7月2日 1:40
  • こんにちは。中川俊輔 です。

     

    zakioさん、回答ありがとうございます。

     

    r-takahaさん、フォーラムのご利用ありがとうございます。

    問題は解決しましたでしょうか?

    有用な情報と思われたため、zakioさんの回答へ回答済みチェックをつけさせていただきました。

     

    回答済みチェックが付くことにより、有用な情報を探している方が情報を見つけやすくなります。
    有用な情報と思われる回答があった場合は、なるべく回答済みボタンを押してチェックを付けてください。

    r-takahaさんはチェックを解除することもできますので、ご確認ください。

     

    それでは!

    2008年7月17日 8:40