https://www.visualstudio.com/downloads/download-visual-studio-vs



Visual Studio 다운로드

다운로드
왼쪽 탐색에서 다운로드 범주를 클릭합니다.
그 다음에 오른쪽 창에서 확인하려는 제품 또는 도구를 선택합니다.

Windows용 Visual Studio 코드

현대적인 웹 및 클라우드 응용 프로그램을 빌드 및 디버깅하기 위해 재정의되고 최적화된 코드 편집 Visual Studio Code는 무료이며 Linux, Mac OSX 및 Windows 중 원하는 플랫폼에서 사용할 수 있습니다.

Mac OS용 Visual Studio 코드

현대적인 웹 및 클라우드 응용 프로그램을 빌드 및 디버깅하기 위해 재정의되고 최적화된 코드 편집 Visual Studio Code는 무료이며 Linux, Mac OSX 및 Windows 중 원하는 플랫폼에서 사용할 수 있습니다.

Linux용 Visual Studio 코드

현대적인 웹 및 클라우드 응용 프로그램을 빌드 및 디버깅하기 위해 재정의되고 최적화된 코드 편집 Visual Studio Code는 무료이며 Linux, Mac OSX 및 Windows 중 원하는 플랫폼에서 사용할 수 있습니다.

ReSharper

제작: JetBrains

ReSharper는 인기 있는 개발자 생산성 확장으로, Microsoft Visual Studio와 호환됩니다. 이 프로그램은 코딩 루틴에서 자동화할 수 있는 대부분의 기능을 자동화합니다. 이 프로그램은 사용자가 입력하는 즉시 컴파일러 오류, 런타임 오류, 중복, 코드 냄새 및 가능한 개선 사항을 찾은 후 지능적인 수정 방안을 제안합니다.

Visual Studio용 Microsoft Azure HDInsight Tools

제작: AmazedSaint

HD Insight Tool 창에서는 HDInsight localhost 또는 Azure Hadoop Hive에 연결하고, Linq To Hive를 수행하기 위한 테이블용 코드를 생성하고, Visual Studio에서 Hive 쿼리를 실행한 후 결과를 볼 수 있습니다.

업데이트 5용 Web Essentials 2013

제작: Mads Kristensen

Web Essentials는 수년 동안 웹 개발자가 원했던 다양한 새 기능을 사용하여 Visual Studio 2013을 확장합니다. CSS, HTML, JavaScript, Markdown, TypeScript, CoffeeScript 또는 LESS를 작성하는 경우에도 개발 작업을 용이하게 해주는 많은 유용한 기능을 찾을 수 있습니다.

Visual Studio 2013용 PowerShell 도구

제작: Adam Driscol

Visual Studio용 PowerShell 도구는 PowerShell의 성능과 Visual Studio 개발 환경의 다양한 이점을 제공합니다.

Visual Studio용 Python 도구

제작: HPCToolsGuy

PTVS는 Visual Studio를 Python IDE로 변환하는 무료/OSS 플러그 인입니다. PTVS는 CPython, IronPython, 편집, 검색, Intellisense, 혼합 Python/C++ 디버깅, 원격 linux/MacOS 디버깅, 프로파일링, 다중 REPL, IPython, Django, Flask, Bottle 뿐만 아니라 Windows, Linux 및 MacOS용 클라이언트 라이브러리를 사용한 클라우드 컴퓨팅을 지원합니다.

Productivity Power Tools 2013

제작: Visual Studio 제품 팀

Visual Studio Professional 이상에 대한 개발자 생산성 향상 확장 기능 모음입니다.

DevExpress

제작: DevExpress

DevExpress ASP.NET 구독을 구성하는 ASP.NET AJAX 컨트롤 및 MVC 확장은 모든 주요 웹 브라우저를 대상으로 하는 광범위한 솔루션의 UI, 분석 및 보고 요구 사항을 해결하도록 설계되었습니다. 지금 당장 무료 평가판을 다운로드하거나 이 구독의 일부로 제공되는 개별 컨트롤 범주를 알아보세요.

Xamarin 플랫폼

제작: Xamarin

Xamarin.Android를 사용하여 C# 및 .NET에서 놀라운 Android 앱을 개발해보세요. Visual Studio에서 Android API에 완전히 액세스하고, 기존 코드와 즐겨찾는 .NET 라이브러리를 다시 사용하고, 앱을 만들고, 빌드하고, 디버깅하고, 배포할 수 있습니다.

Visual Studio 2013 Tools for Unity

제작: Microsoft

Unity 3D 게임의 코드를 Microsoft Visual Studio에서 작성하고 디버그하세요.

GitHub Extension for Visual Studio

제작: GitHub

GitHub Flow를 Visual Studio로 가져오는 Visual Studio 확장 기능입니다.

Team Foundation Server용 Team Explorer Everywhere 2015

Team Foundation Server용 Team Explorer Everywhere 2015에는 Eclipse 플러그 인과 Visual Studio Team Foundation Server, Team Foundation Service 및 Visual Studio Online용 플랫폼 간 명령줄 클라이언트가 포함되어 있습니다.


Team Foundation Server용 Team Explorer Everywhere 2015 - 다국어

Visual Studio 2013 업데이트 5(Visual Studio 2013.5)

Visual Studio 2013 업데이트는 주요 제품 릴리스에 언제나 새 기능을 추가하여 고객에게 끊임없는 가치를 제공합니다. 이러한 릴리스는 시장의 핵심 소프트웨어 개발 동향에 발맞추어 개발자 및 개발 팀이 항상 최신 응용 프로그램을 빌드하는 데 필요한 최적의 솔루션에 액세스할 수 있도록 합니다.

Visual Studio 2013에 대한 지원은 Visual Studio 2013 서비스 팩인 이 현재 업데이트에 대해서만 제공됩니다. 2013년 11월에 릴리스된 Visual Studio 2013 RTM 버전은 이 현재 업데이트 릴리스 후 1년 동안만 지원됩니다. 자세한 내용은 Microsoft 지원 수명 주기 정책을 참조하세요.

자세한 내용은 Visual Studio 릴리스 정보Visual Studio 업데이트 기술 자료 문서를 참조하세요.

다음과 같은 다른 제품에 대한 업데이트도 사용할 수 있습니다.

이 업데이트는 Visual Studio 2013의 일련의 누적 기능 추가 및 버그 수정 중 최신 버전입니다.

형식 선택: 웹 설치 관리자 ISO
Visual Studio 2013 업데이트 5 - 다국어

Microsoft .NET Framework 4.5.1 개발자 팩

.NET Framework 4.5.1 개발자 팩은 .NET Framework 4.5.1용 멀티 타기팅 팩을 설치합니다. 개발자는 Visual Studio 2012 또는 타사 IDE를 사용하여 .NET Framework 4.5.1을 대상으로 지정하는 응용 프로그램을 빌드할 수 있습니다. .NET Framework 4.5.1을 재배포하려면 이 패키지 대신에 웹 설치 관리자를 다운로드해야 합니다.


Microsoft .NET Framework 4.5.1 개발자 팩 - 다국어

Visual Studio Community 2013 업데이트 5

Visual Studio Community 2013은 무료로 제공되고 모든 기능을 갖춘 IDE로, 강력한 코딩 생산성 기능, Windows, iOS 및 Android용 플랫폼 간 모바일 개발 도구, 그리고 수천 개의 확장에 대한 액세스를 제공합니다. 이 Visual Studio 버전은 비 엔터프라이즈 응용 프로그램 개발에 무료로 사용할 수 있습니다. 설치 후 Visual Studio 갤러리를 확인하세요. 도구, 컨트롤 및 템플릿에 빠르게 액세스하여, Visual Studio를 최대한 활용할 수 있도록 해줍니다.

참고: Visual Studio Community 2013(원본 릴리스 버전)이 이미 설치되어 있는 상태에서 이 다운로드를 실행하면 업데이트 5만 설치됩니다. Visual Studio Community 2013이 설치되어 있지 않은 상태에서 이 다운로드를 실행하면 Visual Studio Community 2013과 업데이트 5가 모두 설치됩니다. 두 경우 모두 Visual Studio 2013 언어 팩(원래 릴리스 버전)도 설치할 수 있습니다.

형식 선택: 웹 설치 관리자 ISO
Visual Studio Community 2013 업데이트 5 - 영어

Visual Studio 2013 언어 팩

Visual Studio 2013 언어 팩은 Visual Studio 사용자 인터페이스에 표시된 언어를 전환하는 데 사용할 수 있는 무료 추가 기능입니다.

언어 선택:
Visual Studio 2013 언어 팩 - 한국어


반응형


아래 프로그램을 돌려보면 릭이 잡히기도 하고 안잡히기도 한다, 즉 프로그램 내에서 _CrtSetDbgFlag 으로는 한계가 있다는 것을 알 수 있다



#include <windows.h>

#include <crtdbg.h>

#include <process.h>

#include <iostream>


UINT WINAPI ProcessIO(LPVOID lpParameter)

{


int* p = new int;


return 0;

}


int _tmain(int argc, _TCHAR* argv[])

{


_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

UINT ulThreadID = 0;

HANDLE m_hThread = (HANDLE) _beginthreadex (NULL, NULL, ProcessIO, NULL, NULL, &ulThreadID);

CloseHandle(m_hThread);

WaitForSingleObject( m_hThread, INFINITE );


return 0;

}












http://happyq.egloos.com/3505278


음... 멀티스레드 프로그램에서 효과가 없다는 것은 Crt Debug함수에 대한 설명이었습니다. 그런 경우엔 LeakDiag 등의 다른 방법을 사용해야 합니다. ^^



Visual Leak Detector - Enhanced Memory Leak Detection for Visual C   *  Visual memory leak detector - 사내양's 개발자 노트 * Native Code에서 Memory Leak을 잡는 방법-1   -  Leak Debugging&#40;1&#41; - CRT 디버그함수를 이용한 메모리 누수&#40;Memory Leak&#41; 탐지하기  * Umdh.exe를 사용하여 메모리 누수를 찾는 방법    - Private Bytes는 프로세스에 할당되었지만 다른 프로세스와 공유하지 않는 총 메모리   - Virtual Bytes는 프로세스가 사용하는 가상 주소 공간의 현재 크기를 바이트로 나타낸 것   - Virtual Bytes를 모니터링하여 가상 메모리가 사용되는지 확인* Debugging Tools for Windows &#40;MSDN&#41;   - Debugging Tools for Windows - Overview &#40;WHDC&#41;* Leak Debugging&#40;2&#41; - LeakDiag로 메모리 누수 디버깅하기 &#40;Debugging Memory Leak with LeakDiag&#41;    - 좋은 툴인 것 같다.

반응형

http://www.codeproject.com/Articles/3134/Memory-Leak-and-Exception-Trace-CRT-and-COM-Leaks





Introduction

With this utility you can simply find memory leaks in your program (CRT and COM-Leaks!). Each leak is displayed with the callstack (including the source line) of the allocation. So, you can easily find leaks, while using the STL. It will also write a file with the callstack if your application crashes (it can also handle stack-overflows!). It almost has no runtime-overhead (runtime-cost). And the best: it is free (GNU Lesser General Public License).

Finding memory leaks

It is easy to implement this in your existing VC code:

  1. Add Stackwalker.cpp and Stackwalker.h to your project.
  2. Include Stackwalker.h in your main source file.
  3. Call InitAllocCheck() right after the beginning of your main.
  4. Call DeInitAllocCheck() just before the end of your main (here all the leaks will be reported).

All the leaks will be listed in the file YouAppName.exe.mem.log in the application directory (only in debug builds; it is deactivated for release builds). This will also activate exception-handling by default (release and debug builds).

Only use exception-handling

If you only want to use exception handing, you need to do the following:

  1. Add Stackwalker.cpp and Stackwalker.h to your project.
  2. Include Stackwalker.h in your main source file.
  3. Call OnlyInstallUnhandeldExceptionFilter() right after the beginning of your main.

If an exception occurs, it will write a file with the callstack in the application directory with the nameYouAppName.exe.exp.log.

Example

A simple example is given below:

#include <windows.h>
#include "Stackwalker.h"

void main()
{
  // Uncomment the following if you only
  // need the UnhandledException-Filter
  // (to log unhandled exceptions)
  // then you can remove the "(De)InitAllocCheck" lines
  //OnlyInstallUnhandeldExceptionFilter();

  InitAllocCheck();

  // This shows how the mem-leak function works
  char *pTest1 = new char[100];

  // This shows a COM-Leak
  CoTaskMemAlloc(120);

  // This shows the exception handling
  // and log-file writing for an exception:
  // If you want to try it, please comment it out...
  //char *p = NULL;
  //*p = 'A'; // BANG!

  DeInitAllocCheck();
}

If you execute this example, you will get a file Appication-Name.exe.mem.log with the following content:

##### Memory Report ########################################
11/07/02 09:43:56

##### Leaks: ###############################################
RequestID:           42, Removed: 0, Size:          100
1: 11/07/02 09:43:56
1: f:\vs70builds\9466\vc\crtbld\crt\src\dbgheap.c(359)
                              +30 bytes (_heap_alloc_dbg)
1: f:\vs70builds\9466\vc\crtbld\crt\src\dbgheap.c(260)
                              +21 bytes (_nh_malloc_dbg)
1: f:\vs70builds\9466\vc\crtbld\crt\src\dbgheap.c(139) +21 bytes (malloc)
1: f:\vs70builds\9466\vc\crtbld\crt\src\newop.cpp(12) +9 bytes (operator new)
1: d:\privat\memory_and_exception_trace\
            memory_and_exception_trace\main.cpp(9) +7 bytes (main)
1: f:\vs70builds\9466\vc\crtbld\crt\src\crt0.c(259)
                               +25 bytes (mainCRTStartup)

**** Number of leaks: 1

##### COM-Leaks: ###############################################
(shortened)
**** Number of leaks: 1

Explanation

Now, I will explain the Memory-Report-File:

RequestID:           42, Removed: 0, Size:          100

This line is the beginning of one leak. If you have more than one leak, then each leak will start with a RequestID.

  • RequestID

    For CRT: This is the RequestID which is passed to the AllocHook. This ID clearly identifies an allocation. The CRT just increments this number for each allocation. You can also use this number with the_CrtSetBreakAlloc function.

    For COM: This is the address of the allocated memory.

  • Removed

    In a memory leak dump this must always be 0 (false).

  • Size

    This is the size of the allocated memory block.

1: f:\vs70builds\9466\vc\crtbld\crt\src\dbgheap.c(359)
                                   +30 bytes (_heap_alloc_dbg)

This is an actual stack entry. The stack is shown from the last function on the top going through each callee until the end of the stack is reached.

  • 1:

    This number is incremented for each complete callstack. You can ignore this.

  • f:\vs70builds\9466\vc\crtbld\crt\src\dbgheap.c

    The actual filename.

  • (359)

    The line number inside the file.

  • +30 bytes

    This is the offset from this line in bytes (if a line produces more than one assembler instruction).

  • (_heap_alloc_dbg)

    The name of the function.

    More options by calling InitAllocCheck

    InitAllocCheck has three parameters:

    Parameter nameDescription
    • eAllocCheckOutput
    • eOutput

    This is an enum for output-format. The following is possible:

    • ACOutput_Simple (default)

      This outputs the callstack as seen above.

    • ACOutput_Advanced

      This has a more detailed output of the callstack. For more info seehere.

    • ACOutput_XML

      This outputs the leaks in an XML file so that you can read it easily from other applications or use some XSLT to transform it to a more readable format you want. For more info see here.

    • BOOL
    • bSetUnhandledExeptionFilter(default: TRUE)

    If this is set, an UnhandledExceptionFilter will be installed. If an (unhandled) exception occurs it will write the callstack in a log file and terminate. For more info see here.

    • ULONG
    • ulShowStackAtAlloc (default: 0)

    Notice: This works only for CRT-allocs.

    Here you can specify the level of mallocs/frees logging. By default nothing will be logged in the log file at runtime. If you need to know what happens while executing the program you can specify a value. Then themalloc/free action will be logged to the file (either with or without callstack).

    Valid values are:

    • 0 = Do not write any output during runtime-alloc-call (default).
    • 1 = Write only the alloc action (mallocreallocfree).
    • 2 = Write alloc action and callstack only for malloc/realloc.
    • 3 = Write alloc action and callstack for all actions.

    Log-output with more info

    You can also get an output with more info about each stack entry. For this you have to call InitAllocCheck with the first parameter set to ACOutput_Advanced. If you execute the following sample you will get a file Appication-Name.exe.mem.log with more info:

    #include <windows.h>
    #include "Stackwalker.h"
    
    void main()
    {
      InitAllocCheck(ACOutput_Advanced);
      // This shows how the mem-leak function works
      char *pTest1 = new char[100];
      DeInitAllocCheck();
    }

    And here is the (shortened) output:

    ##### Memory Report ########################################
    11/04/02 09:04:04
    
    ##### Leaks: ###############################################
    RequestID:           45, Removed: 0, Size:          100
    1: 11/04/02 09:04:04
    // ...
    1:   5     main +49 bytes
    1:     Decl: main
    1:     Line: d:\privat\memory_and_exception_trace\main.cpp(27) +7 bytes
    1:     Mod:  Memory_and_Exception_Trace, base: 00400000h
    
    1:   6     mainCRTStartup +363 bytes
    1:     Decl: mainCRTStartup
    1:     Line: f:\vs70builds\9466\vc\crtbld\crt\src\crt0.c(259) +25 bytes
    1:     Mod:  Memory_and_Exception_Trace, base: 00400000h
    
    1:   7     _BaseProcessStart@4 +35 bytes
    1:     Decl: _BaseProcessStart@4
    1:     Mod:  kernel32, base: 77e40000h
    
    **** Number of leaks: 1
    // ...

    Explanation

    Here, I will explain the Memory-Report-File:

    RequestID:           45, Removed: 0, Size:          100

    This line is the same as above:

    1:   5     main +49 bytes
    • 1:

      This number is incremented for each complete callstack. You can ignore this.

    • 5

      This is the depth of the callstack. This number is incremented for each stack entry. The stack is shown from the last function on the top (number 0) going through each callee until the end of the stack is reached.

    • main +49 bytes

      The number of bytes from the beginning of this function, where the instruction for this callstack is stored.

    1:     Decl: main
    1:     Line: d:\privat\memory_and_exception_trace\main.cpp(27) +7 bytes
    1:     Mod:  Memory_and_Exception_Trace, base: 00400000h
    • Decl: main

      This is the declaration of the function.

    • Line: ....xyz.cpp(27) +7 bytes

      This shows the actual line (in brackets) of the callstack (here: line 27). In addition, it gives the offset from this line in bytes (if a line produces more than one assembler instruction).

    • Mod: Memory_and_Exception_Trace

      The name of the module (EXE, DLL, OCX, a.s.o.).

    • base: 00400000h

      The base address of this module.

    XML output

    If you set the first parameter to ACOutput_XML an XML file will be produced. It has the following contents:

    <MEMREPORT date="11/08/02" time="10:43:47">
      <LEAK requestID="47" size="100">
        <!-- shortened -->
        <STACKENTRY decl="main" decl_offset="+100"
                        srcfile="d:\...\main.cpp" line="16"
          line_offset="+7" module="Memory_and_Exception_Trace" base="00400000"/>
        <STACKENTRY decl="mainCRTStartup" decl_offset="+363"
                        srcfile="f:\...\crt0.c" line="259"
          line_offset="+25" module="Memory_and_Exception_Trace" base="00400000"/>
      </LEAK>
    </MEMREPORT>

    It is pretty self explaining if you take a look at the "advanced log output".

    Mem-leak-analyse tool

    If you are using the XML-output format then you can use my MemLeakTool to display the leaks in a sorted order (sorted by callstack). Just select the "xml-leak"-File and press "Read". The callstack will be displayed in a TreeView. If you select a node, the source code will be shown in the right part (if it could be found).

    Information: This program requires .NET Framework 1.0!

    A word on leaks

    You should be aware, that some leaks might be the result of other leaks. For example the following code throws two leaks, but if you remove the "originator" of the leaks, the other leak will also disappear. For example:

    #include <windows.h>
    #include <stdlib.h>
    #include "stackwalker.h"
    class MyTest
    {
      public:
        MyTest(const char *szName)
        {
          // The following is the second resulting leak
          m_pszName = strdup(szName);
        }
        ~MyTest()
        {
          if (m_pszName != NULL)
            free(m_pszName);
          m_pszName = NULL;
        }
      protected:
        char *m_pszName;
    };
    
    void main()
    {
      InitAllocCheck();
    
      // This is the "main" leak
      MyTest *pTest = new MyTest("This is an example");
    
      DeInitAllocCheck();
    }

    How it works (CRT)

    The basis of the memory leak logger is a Hashtable with information about all the allocated memory (including callstack). Basically _CrtSetAllocHook is called to hook all the memory allocations / frees. Therefore only C/C++ allocations are logged. On every allocation a portion of the callstack and the Instruction-Pointer is caught and stored in the Hashtable, with some other information about the allocation.

    If the application calls DeinitAllocCheck then the Hashtable will be iterated and the (saved) callstack of all the entries will be listed in the file. For this we provide a pointer to our ProcessMemoryRoutine function to theStackWalk function.

    In detail

    Hashtable

    The Hashtable contains by default 1024 entries. You can change this value if you are doing many allocations and want to reduce the collisions. Just change the ALLOC_HASH_ENTRIES define.

    As hash-key, the lRequestID for each allocation is used. This ID is passed to the AllocHook function (at least forallocs). If it is not passed (for example, for freeing), then an (valid) address is passed. By having this address it is also possible to get the lRequestID, by looking into the _CrtMemBlockHeader of the allocated block.

    For hashing, a very simple and fast hash-function is used:

    static inline ULONG AllocHashFunction(long lRequestID) {
      return lRequestID % ALLOC_HASH_ENTRIES;
    }  // AllocHashFunction

    Insert an allocation into the Hashtable

    If a new allocation should be inserted into the Hashtable, first a thread context for the actual thread is made by callingGetThreadContext. This function requires a "real" thread handle and not a pseudo handle which is returned byGetCurrentThred. So, for this I have to create a "real" handle by calling DuplicateHandle.

    Actually, I only need the current Ebp and Eip registers. This could also be done by just reading the registers with the inline assembler. Now having the registers, I read the memory at the specified address. For Eip, I only need to read 4 bytes. I do not know why StackWalk needs to read the Eip values, but if the values could not be read fromStackWalk it fails to build the callstack. The real important part is the callstack which is stored in the memory pointing from Ebp (or Esp).

    At the moment, I just try to read 0x500 bytes by calling the ReadProcessMemory function. I don't read the complete stack, because it might use too much memory for many allocations. So, I reduced the maximum size to 0x500. If you need a deeper callstack, you can change the MAX_ESP_LEN_BUF define.

    If the callstack is not 0x500 bytes deep, then the ReadProcessMemory will fail with ERROR_PARTIAL_COPY. If this happens, I need to ask how many are possible, to read without any error. For this I need to query this value by callingVirtualQuery. Then, I try to read as many bytes as possible.

    Having the callstack I can simply insert the entry into the Hashtable. If the given hash-entry is already occupied, I make a linked list and append this entry to the end.

    Building the leak-list

    If you call DeInitAllocCheck I simply walk through the Hashtable and output every entry which was not freed. For this I call StackWalk with a pointer to my own memory-reading-function (ReadProcMemoryFromHash). This function is called from the internals of StackWalk. If it is called it looks up the Hashtable for the given lRequestID and returns the memory which was stored in the Hashtable. The lRequestID is passed in the hProcess parameter of theStackWalk function (as stated in the documentation of StackWalk).

    Ignoring allocations

    Allocations/frees for _CRT_BLOCK are ignored (for more info, see here). This is because CRT dynamically allocates some memory for "special purposes". The tool also checks the _CRTDBG_ALLOC_MEM_DF flag of the _crtDbgFlag variable. If it is off, then all the allocations are ignored. For more details see _CrtSetDbgFlag.

    How it works (COM)

    To track COM-memory-leaks, you have to provide an IMallocSpy interface. This interface must be registered withCoRegisterMallocSpy. After that the (own) IMallocSpy instance is called for every memory (re)allocation/free. So, you can track all memory actions.

    The storage of the callstack is done in the same way as for CRT-allocs (in a Hashtable). So, for more info please read the CRT-section.

    A word on COM-leaks

    Actually, there is nothing to say, but...

    If you are using MSXML 3 or 4 implementation, you have to be aware of the fact that this parser uses a "smart" pseudo-garbage collector. This means that they allocate memory and will not free it after it is used! So, you may see some leaks which are only "cached memory". If you first call CoUninitialize, then all the cached memory will be freed and the "real" COM-leaks will be reported.

    For more info see: Understanding the MSXML Garbage Collection Mechanism.

    MFC usage

    The problem with MFC is that the derived CWinApp class is instantiated by the C-runtime, because it is a global variable. The easiest solution to implement the Leak-Finder is to declare the following static struct inside yourMainApp.cpp.

    You also have to add stackwalk.cpp and stackwalk.h to your project. You also need to add the #include<stdafx.h> on top of the stackwalk.cpp file (if you use precompiled headers). A sample of an MFC application is also available from the top of this article:

    static struct _test
    {
      _test()
      {
        InitAllocCheck();
      }
    
      ~_test()
      {
        DeInitAllocCheck();
      }
    } _myLeakFinder;

    Temporarily disable logging (only CRT)

    When you don't want to log a special allocation of your application (for whatever reason; MFC does this often), then you can simply deactivate it by disabling the CRT flag _CRTDBG_ALLOC_MEM_DF with the _CrtSetDbgFlag function. Here is an example of how you can do this:

    #include "Stackwalker.h"
    
    #include <crtdbg.h>
    
    bool EnableMemoryTracking(bool bTrack)
    {
      int nOldState = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
      if (bTrack)
        _CrtSetDbgFlag(nOldState | _CRTDBG_ALLOC_MEM_DF);
      else
        _CrtSetDbgFlag(nOldState & ~_CRTDBG_ALLOC_MEM_DF);
      return nOldState & _CRTDBG_ALLOC_MEM_DF;
    }
    
    void main()
    {
      InitAllocCheck();
    
      // The following will be logged
      char *pTest1 = new char[100];
    
      EnableMemoryTracking(false);  // disable logging
      // The following will NOT be logged
      char *pTest2 = new char[200];
      EnableMemoryTracking(true);  // enable logging
    
      // The following will be logged
      char *pTest3 = new char[300];
    
      DeInitAllocCheck();
    }

    Unhandled exceptions

    There are three ways to use this tool for unhandled exceptions.

    Simple using

    If you just call InitAllocCheck with no parameters or with the second parameter set to TRUE, then an unhandled exception filter will be installed. If an unhandled exception occurs, a log file with the callstack will be written, a dialog box with the exception message will be displayed, and the application will be terminated with FatalAppExit.

    Second simple using

    If you don't want the AllocCheck-overhead (the (small) overhead is only present in debug builds), you can simply callOnlyInstallUnhandeldExceptionFilter. This will install the UnhandledExceptionFilter which writes a log file if an (unhandled) exception occurs. The log file will be stored in the application directory with the nameYouAppName.exe.exp.log:

    int main()
    {
      OnlyInstallUnhandeldExceptionFilter();
    
      // do your main code here...
    }

    Advanced using

    You can write your own exception filter and just call StackwalkFilter to produce the callstack. Then you can do whatever you want. Here is a small example:

    static LONG __stdcall MyUnhandlerExceptionFilter(EXCEPTION_POINTERS* pExPtrs)
    {
       LONG lRet;
       lRet = StackwalkFilter(pExPtrs,
                 EXCEPTION_EXECUTE_HANDLER, _T("\\exception.log"));
       TCHAR lString[500];
       _stprintf(lString,
          _T("*** Unhandled Exception!\n")
          _T("   ExpCode: 0x%8.8X\n")
          _T("   ExpFlags: %d\n")
          _T("   ExpAddress: 0x%8.8X\n")
          _T("   Please report!"),
          pExPtrs->ExceptionRecord->ExceptionCode,
          pExPtrs->ExceptionRecord->ExceptionFlags,
          pExPtrs->ExceptionRecord->ExceptionAddress);
       FatalAppExit(-1,lString);
       return lRet;
    }
    
    int main()
    {
      InitAllocCheck(ACOutput_Advanced, FALSE);
      SetUnhandledExceptionFilter(MyUnhandlerExceptionFilter);
    
      // do some stuff...
    
      DeInitAlloocCheck();
    }

    Common mistakes

    One of the most common mistakes while using this tool is that you statically instantiate classes in your main function. The problem is that the destructor of the class is called after the call to DeInitAllocCheck. If some memory was allocated inside this class, this memory will appear as a leak. For example:

    #include <windows.h>
    #include "Stackwalker.h"
    #include <string>
    
    void main()
    {
      InitAllocCheck();
      std::string szTemp;
      szTemp = "This is a really long string";
      DeInitAllocCheck();
    }

    There are two solutions for this. You can start a block after the call to InitAllocCheck and end it before the call toDeInitAllocCheck. With this you can be sure that the destructors are called before the leak file is produced. For example:

    #include <windows.h>
    #include "Stackwalker.h"
    #include <string>
    
    void main()
    {
      InitAllocCheck();
      {
        std::string szTemp;
        szTemp = "This is a really long string";
      }
      DeInitAllocCheck();
    }

    The second solution is to use the same technique that is used for MFC applications (see above).

    Visual Studio 7 and Win2K / NT

    I found a problem with the executables built with VS7 and run on Win2K or NT. The problem is due to an old version ofdbghelp.dll. The PDB files generated from VS7 are in a newer format (DIA). It appears that the VS installations do not update dbghelp.dll on Win2K. So the original version (5.0.*) is still on the system and will be used. But with this version it is not possible to read the new PDB format. So, no callstack can be displayed.

    To get it to work you have to do the following

    Download the latest Debugging Tools for Windows (which includes dbghelp.dll). You have to install it to get the files. But you only need the dbghelp.dll! Now we have another problem. The installer does not replace the originaldbghelp.dll. So we need to copy the dbghelp.dll in our EXE dir. Now to make sure the right version is loaded you have to put a file with the name appname.local in your EXE dir (please replace appname with the EXE name (without extension)). Now it should also work on WinNT/2K.

    Known issues

    • The memory leak works correctly only if the lRequestID does not wrap (32-bit value). If the value wraps around, then it is not possible to clearly assign a given lRequestID to a previous allocation, because it is possible that this ID was used twice (or even more). But this happens only with VC7, because VC6 has a bug in the C-runtime which will call _DbgBreak if the lRequestID wraps (if no _CrtBreakAlloc is used).
    • If you compile with "Detect 64-bit portability issues (/Wp64)" option on VC7, it will generate a warning.
    • If you use this tool in managed C++ it will not correctly display the callstack for managed code.
    • For some reason, the COM-alloc-callstack cannot display the stack-entry which really calls theCoTaskMemAlloc function. Only the upper stack entry can be shown.

    반응형



    http://cafe.naver.com/xheaven/205


    1.LeakDiag
       사용 시나리오 : 메모리 누수 탐지 툴
       다운로드 주소 : 
       ftp://ftp.microsoft.com/pss/tools/developer support tools/LeakDiag/leakdiag125.msi

    2. Debugging Tools for Windows
    사용 시나리오 : 디버거와 툴의 모임
    다운로드 주소 :
    커스텀 디버거 익스텐션을 작성하기 위해서는 커스텀 설치와 SDK 모두 설치를 해야한다.
      1) UMDH
          사용 시나리오 : 메모리 누수 탐지
      2) gFlags
          사용 시나리오 : 구성 설정

    3.Microsoft Application Verifier

    사용 시나리오 :일반 어플리케이션 문제 해결
    다운로드 주소 : 

    4.프로세스 익스플로러(Process Explorer)
     사용 시나리오 : 시스템과 프로세스의 전반적인 상태 분석
     다운로드 주소 :
     
    5.프로세스 모니터 (Process Monitor)
    사용 시나리오 : 파일 시스템과  레지스트리, 프로세스와 스레드 동작을 보여주는 감시툴
    다운로드 주소 :

    6.윈도우 드라이버 킷 (WDK)
    사용시나리오 : 일반 개발
    다운로드 주소 :

    7.Wireshark
    사용시나리오 : 네트워크 프로토콜 분석기
    다운로드 주소:

    8.DebugDiag
    사용 시나리오 : 프로세스 문제(메모리 누수와 크래시)해결
    다운로드 주소:

    반응형

    http://www.borland.com/products/devpartner/


    http://www.borland.com/products/devpartner/try/devpartnervisualcboundscheckersuite.aspx 에서 작성하고 다운 받을 수 있다 [트라이얼임]

    반응형



    http://www-01.ibm.com/software/awdtools/purify/


    Rational Purify

    Rational software

    Product line

    Rational® Purify® is a dynamic software analysis tool designed to help developers write more reliable code. It includes two capabilities: 1) Memory debugging (pinpoints hard to find memory errors such as uninitialized memory access, buffer overflow and improper freeing of memory), 2) Memory leak detection (identifies memory blocks that no longer have a valid pointer). Purify is supported on Windows®, Linux®, Solaris®, and AIX®.

    Product Editions

    Compare editions

    Purify for Linux and UNIX

    Dynamic software analysis tool for UNIX application development

    Purify for Windows

    Dynamic software analysis tool for Windows application development

    반응형

    http://www.slideshare.net/hebory/11-0730-gpg-2111

    반응형

    반응형

    http://cafe.naver.com/totallab/444




    addmysym.bat





    처음에는 C:\MySymbol에 심볼 파일을 하나씩 복사하고 사용하지만 점점 모듈 수가 많아지고 관리하는 버전이 많아지면 심볼 스토어를 설정해 더 편리하게 사용할 수 있습니다.

     

    심볼 스토어(Symbol Store)란 모든 심볼 파일을 모아 놓고 해당 위치를 심볼 경로로 지정하면 디버깅하는 모듈의 심볼 파일이 저절로 찾아져서 매번 심볼 파일을 찾고 복사하는 작업을 할 필요가 없습니다.

    <?xml:namespace prefix = o /><?xml:namespace prefix = o /> 

    C:\MySymbols 에 매번 빌드한 심볼 파일을 심볼 스토어 형식으로 더하면 C:\MySymbols 에는 내가 개발하는 모듈의 모든 버전에 대한 심볼 파일들이 체크섬에 따라 분류되어 쌓이게 됩니다새로 빌드한 심볼 파일의 복사가 실패하지도 않고 과거 버전의 심볼 파일들도 유지되므로 과거 버전의 디버깅도 가능해집니다.

     

    책에서 심볼 파일을 더하기 편하게 배치 파일을 만드는 방법을 제시하고 있습니다배치 파일 내부에서 symstore.exe를 사용하는데이것은 WinDbg 폴더에 있는 심볼 스토어 유틸리티 입니다. WinDbg 경로를 환경 변수에 지정해 놨으므로 배치 파일상에서 그냥 symstore.exe를 실행하면 됩니다.

     

    C:\symstore add /f c:\Exam\Ch2\Src\MyApp\Release\MyApp.pdb /s C:\MySymbols /t Myproduct

     

    /f 뒤에는 복사할 심볼 파일 경로를 지정하고, /s 뒤에는 복사될 위치를 지정합니다. /t는 제품 이름을 넣습니다매번 모든 옵션을 타이핑하기는 귀찮으므로 심볼 파일만 파라미터로 받게 ddMySym.bat 배치 파일을 만듭니다.(참고로 배치 파일 만드는 방법은 위에 한 줄 소스를 메모장으로 복사후 확장자를 bat으로 저장하시면 됩니다.)

     

     

     

    Symstore add /f %1 /s C:\MySymbols /t MyProduct

     

    이 배치 파일을 C:\Utility에 넣었다면 다음과 같이 사용합니다.

     

    C:\Utility\AddMySym c:\Exam\Ch2\Src\MyApp\Release\MyApp.pdb

     

     

     

     

     

    편하게 사용하려면 이 배치 파일을 놓고심볼 파일을 드래그 앤 드롭하면 됩니다. WinDbg에서 사용할 때는 심볼 경로에 C:\MySymbols를 추가해 놓으면 됩니다.

     

    덧붙이자면 네트워크 폴더를 심볼 스토어로 사용하면 팀 프로젝트의 생산성을 더욱 향상시킬 수 있습니다.

    반응형


    http://tudul2box.tistory.com/317


    윈도우를 사용하다보면 이유없이 실행창이 꺼지는 현상을 많이 경험해 보았을 것이다.

    이때 오류 분석파일(덤프)을 생성할 수 있는 프로그램을 사용하여 오류를 분석하는데,

    마이크로 소프트사에서 제공해주는 Debug Diagnostic Tool을 이용하면 된다.

     

    windbg 프로그램과 다른 점은 windbg는 직접 실행하고 프로세스가 끝날때마다 설정을 해주어야 하지만,

    이 프로그램을 서비스로 실행되어 충돌(crash)가 발생하면 자동으로 지정 폴더에 저장해준다.



    http://www.microsoft.com/en-us/download/details.aspx?id=26798







    http://byung.egloos.com/4743470

    [Troubleshooting Tool] Debug Diagnostic Tool Windows debugging

    Debug Diagnostics Tool AD+ 와 같이 특정한 문제에 대해서 Memory Dump를 수집할 수 있는 기능을 제공한다여기서 특정한 문제라는 것은 Hang/Performance 문제/Memory 누수/Virtual Memory 조각화 및 다양한 Crash Issue이다뿐만 아니라 Crash Memory 관련 문제에 대해서 분석 report를 제공한다는 점에 있어서 유용하다.

     

    먼저, Crash Rule에서 보면따로 설정하지 않은 1st Chance Exception에 대한 설정을 할 수 있다아래의 그림과 같이 Action Type으로 Log를 남기거나 Mini Dump  Full Dump를 수집할 수 있도록 설정가능하며, dump 생성의 수를 제한할 수 도 있다. (만일, 0라고 설정하면 제한하지 않는 다는 의미이다.) Performance를 고려하여 대부분 None이거나 간혹 Log 정도를 남기게 된다.

    그리고임의의 1st Exception에 대한 Dump 수집을 설정할 수 있다. (이 말은 기본적으로 아무 설정을 하지 않았을 때, 2nd chance exception에 대한 Crash Dump가 기본적으로 수집된다이는 상위 그림의 Advances Settings Exceptions 버튼을Click하여 설정한다.

    상위의 그림은 좌측의 Exception Code AV Click 하여 1st Chance AV가 발생했을 때 자료를 어떻게 수집할 지 설정하는 방법이다앞서서 설명한 것처럼 Action Type Log Mini  Full User Dump를 수집할 수 있도록 설정할 수 있다특이한 경우는 CLR Exception의 경우이다.

    보면, .NET Exception Type 이라는 부분이 존재한다여기에 Exception 정보를 추가하면해당하는 Exception 에 대해서 Full User Dump를 수집하도록 설정된다.

     

    Advanced Settings에 또 한가지는 Break point 를 설정하여 Dump를 수집할 수 있다는 것이다다음의 그림을 보자.

    기본적으로 list Kernel32!ExitProcess나 몇 가지가 추가되어 있다일반적으로 2nd Chance Exception으로 인하여 Process terminated 되는 경우에 Crash Dump를 수집하므로, Kernel32!ExitProcess list에서 선택하고 Action Type Full user Dump로 설정하여 Crash Rule 을 완성한다하지만외에 원하는 부분에 BP를 설정하고 Dump를 수집하거나 Log를 남기고 싶을 경우에는 상위의 그림과 같이 Breakpoint Expression 부분에 원하는 address를 설정하여 추가시킬 수도 있다.

     

    그리고, Heap Corruption되는 증상에 대해서 일반적으로 Pageheap Enabled 하고 Crash Dump를 수집하게 되는 데, Debug Diagnostic Tool에서는 Advanced Settings PageHeap Flags 라는 부분에서 PageHeap을 설정할 수 있다.

    Debug Diagnostic Tool Process Memory Leak 현상을 Detection 하기 위해서 Leaktrack.dll injection 시켜서 Leak tracking 할 수 있는 기능이 존재한다.

    Processes Tab을 확인해 보면, Process ID에 따른 Process list 정보를 알 수 있는 데, Leak으로 의심이 되는 Process를 선택하여 오른쪽 마우스를 Click 하면, Monitor For Leaks 라는 Menu를 확인할 수 있다이는 앞서서 설명한 Leaktrack.dll을 해당 Process Injection 시키는 역할을 한다이후에 Private Bytes의 증가를 유심히 확인하여 충분히 메모리가 지속적으로 증가하는 패턴이 확인되면, Create Full Userdump menu 를 통해 메모리 dump를 수집할 수 있다간혹 Memory Leak으로 인하여 Out Of Memory Exception이나 Crash를 동반하는 경우가 있으므로, Crash Rule Kernal32!ExitProcess  Full user dump와 함께 leaktrack을 걸어 놓는 것도 좋을 듯 하다.

     

    ** 메모리 Leak?

    Return 되지 않는 resource 로 인하여 process가 점유하고 있는 메모리가 지속적으로 증가하는 현상을 말한다. Logic에 따라서 Application이 메모리를 보유하고 사용할 수도 있으므로이와는 구분 되어야 한다이 경우시스템 resource가 부족하여 시스템의 전반적인 performance에 영향을 줄 수 있으며간혹 Hang 증상이 발생할 수 있다메모리 Leak을 판단하기 위해서는 메모리의 증가하는 패턴이 꾸준히 발생하기 때문에 성능로그의 Private Bytes  Virtual Bytes 그리고, Working Set의 데이터 패턴을 보고 Leak 여부를 판단해야만 한다.

    *******

     

    Debug Diagnostic Tool은 다음과 같은 메모리 할당에 대한 Tracking이 가능하다.

    1)    NT Heap allocator

    1.     HeapAlloc

    2.     LocalAlloc

    3.     GlobalAlloc

    2)    Virtual Memory allocator

    1.     VirtualAlloc

    3)    C Run time memory allocator

    1.     malloc

    2.     calloc

    3.     operator new

    4)    BSTR allocator

    1.     SysAllocString

    5)    OLE/COM allocator

    1.     CoTaskMemAlloc, IMalloc interface

     

    Debug Diagnostic Tool이 제공하는 기능 중에 Crash Dump  Memory Dump 분석하여 reporting을 출력해주는 기능을 가지고 있다.

    그림에서처럼 Advanced Analysis Tab에는 Crash memory analysis를 선택할 수 있다분석에 앞서서 Symbol을 정확하게 맞춰주는 것이 필요한데, tools menu의 Options and Settings  를 통해서 설정할 수 있다.

    Symbol Search path For analysis 에는 default Microsoft Public Symbol이(http://msdl.microsoft.com/download/symbols, 그리고, C:\symcache directory를 local machine의 symbol cache로 사용하도록 ) 설정되어 있다그리고필요한 symbol path Symbol Search Path for Debugging에 위치시켜야만 Symbol이 맞지 않아서 잘못된 reporting이 출력되는 것을 방지할 수 있다.

     

    Debug Diag는 다음과 같은 Memory leak 관련 report 를 출력한다.

    보면, Analysis summary에서 눈에 띄게 Memory를 보유하고 있는 Function Call Check할 수 있다상위 report에서는 asp.dll VBScript.dll 과 관련한 Callstack에서 메모리를 보유하고 있음을 보여주고 있는 데해당 Function Click 하면, 어떤 Callstack에 메모리 할당이 이뤄졌는지 다음과 같이 reporting 하고 있음을 확인할 수 있다. 그림에서는 안 나타나 있지만, sample callstack 정보와 더불어 단위 Allocation size와 Allocation Count에 따른 unfreed memory에 대한 Top 10 list of allocations 정보를 출력해 줌으로써 Allocation pattern을 알 수 있다.

    그리고다음은 Application에서 사용하고 있는 Virtual Memory에 대한 정보이다. 아래 그림에서도 알 수 있지만, Application 전반적으로 Reserved/Commited 그리고 Free 영역에 대한 사용정도를 알 수 있다. 그리고, Virtual Memory Details에서는 Application 에서 VirtualAlloc이 얼마나 되는 지, Threads가 사용한 Memory 또는 Native Heap으로 사용된 메모리가 많은 지에 대한 정보를 제공한다. 

    Heap Memory의 경우는 다음과 같이 따로 정보를 제공한다. 각 Heap의 종류에 따라(예를 들어, Application에서 필요에 따라 Heap을 따로 관리하는 경우가 많은 데, default Heap 외에 crt heap이나 odbc나 oledb가 사용하는 mpheap 등이 존재할 수 있다.) 어느정도의 memory가 reserved 되어 있는 지, commit 되어 있는 지 보고해주며, 또한 Heap block에 따른 Address 정보나 세부적으로 memory의 할당여부를 확인할 수 있다. 이러한 Heap block의 정보를 가지고 의심이 나는 Heap 영역에 어떤 Data가 존재하는 지를 Memory Dump에서 Windbg를 통해 확인해 볼 수 있기 때문에 유용하다.  

    위의 그림에서도 나타나 있지만, Virtual Memory나 Heap Memory에 대한 Allocation 정보에서의 Top 10 List of allocations 보다 직관적으로 unfree된 pattern을 알 수 있는 유용한 정보이다. 그러므로, 이러한 Heap이나 Virtual Memory에 대한 정보는 Application의 메모리 누수인지 아닌지에 대한 판단 및 누수일 때의 원인을 찾는 데 도움을 줄 수 있다

    그리고, 추가적으로 Handle count에 대한 정보를 출력해줌으로써 Handle leaks에 대한 tracking도 가능하고, IIS Hang과 같은 Issue를 위해 HTTP Ping을 주기적으로 설정하는 기능도 존재한다.






    http://www.microsoft.com/en-us/download/details.aspx?id=26798



    The Debug Diagnostic Tool (DebugDiag) is designed to assist in troubleshootingissues such as hangs, slow performance, memory leaks or fragmentation, and crashes in any user-mode process. The tool includes additional debugging scripts focused on Internet Information Services (IIS) applications, web data access components, COM+ and related Microsoft technologies.

    Quick details

    Version:1.2Date published:7/14/2011
    Language:English

    Files in this download

    The links in this section correspond to files available for this download. Download the files appropriate for you.

    File nameSize
    DebugDiagx64.msi16.1 MBDOWNLOAD
    DebugDiagx86.msi11.7 MBDOWNLOAD

    Overview

    The Debug Diagnostic Tool (DebugDiag) is designed to assist in troubleshooting issues such as hangs, slow performance, memory leaks or memory fragmentation, and crashes in any user-mode process. The tool includes additional debugging scripts focused on Internet Information Services (IIS) applications, web data access components, COM+ and COM+ related Microsoft technologies, Sharepoint, and .NET framework.

    • DebugDiag 1.0 was released as part of the IIS Diagnostic Toolkit and as a standalone tool (x86 only).
    • DebugDiag 1.1 was released as a standalone tool only (x86 and limited x64 support).
    • DebugDiag 1.2 is currently available as a standalone tool only (x86 and full x64 support).
    DebugDiag provides an extensible object model in the form of COM objects and provides a script host with a built-in reporting framework. 

    It is composed of the following 3 components: a debugging service, a debugger host, and the user interface.

    The Debugging Service The debugger service (DbgSvc.exe) performs the following tasks:
    • Attach/Detach the host to processes
    • Collect performance monitor data
    • Implement HTTP ping to detect hangs
    • Inject leak monitor into running processes
    • Collect debugging session state information
    • Shows the state of each rule defined
    The Debugger Host The Debugger Host (DbgHost.exe) hosts the Windows Symbolic Debugger Engine (dbgeng.dll) to attach to processes and generate memory dumps. It also hosts the main analyzer module to analyze memory dumps. Dbghost.exe has no dependency on the service “DbgSvc.exe” and can be used separately. The User Interface The user interfaces (DebugDiag.exe and DebugDiagAnalysisOnly.exe) present an interface to analyze memory dumps, automate the creation of control scripts and to show the status of running processes, including services. It is composed of 3 views: 

    • Rules: Creates control script for the debugger host through a wizard. The script is located under the directory \scripts.
    • Advanced Analysis: Runs a selected “Analysis Script” against one or more memory dumps.
    • Processes: Shows status of running processes/services.
    Note: DebugDiagAnalysisOnly.exe does not require privilege elevation on operating systems beginning with Windows Vista, so it only contains the Advanced Analysis view.

    Top of pageTop of page

    System requirements

    Supported operating systems: Windows 7

    • Windows 2003-Windows XP • Windows 2008-Windows Vista • Windows 2008 R2- Windows7

    Top of pageTop of page

    Instructions

    Please visit Microsoft KB 2580960 for detailed instruction on how to use Debugdiag 1.2.

    Debugdiag 1.2 introduced many new features that proved to be of great value:

    Analysis:

    • .Net 2.0 and higher analysis integrated to the Crash Hang analysis.
    • SharePoint Analysis Script.
    • Performance Analysis Script.
    • .NET memory analysis script (beta).
    • Native heap analysis for all supported operating systems
    Collection:
    • Generate series of Userdumps.
    • Performance Rule.
    • IIS ETW hang detection.
    • .NET CLR 4.0 support.
    • Managed Breakpoint Support.
    • Report Userdump generation to the Event log.
    Deployment
    • Import/Export of rules and configuration, including 'Direct Push' to remote servers.
    • Enterprise deployment support using XCopy and Register.bat.

    Please direct any questions, comments or feedback to dbgdiag@microsoft.com




    반응형

    + Recent posts