기본 콘텐츠로 건너뛰기

Visual Leak Detector - Enhanced Memory Leak Detection for Visual C++

Sample Image - screenshot.png

What's New

30 March 2005 - Version 0.9d has been newly released. This is a fairly major release that features significant changes to the way VLD interfaces with the application being debugged. With this release, VLD is now packaged in library form. Packaged as a pre-built library, it is now much easier to start using VLD with your projects because it no longer requires you to set-up your build environment in any particular way. For example, you'll no longer need to have the Platform SDK installed in order to use VLD. You also won't need to configure Visual C++'s include search path to include directories in any specific order.

Introduction

This memory leak detector is superior, in a number of ways, to the memory leak detection provided natively by MFC or the Microsoft C runtime library. First, built-in leak detection for non-MFC applications is not enabled by default. It can be enabled, but implementing it is not very intuitive and (for Visual C++ 6.0 at least) it doesn't work correctly unless you fix a couple of bugs in the C runtime library yourself. And even when it is working correctly its capabilities are somewhat limited. Here is a short list of capabilities that Visual Leak Detector provides that the built-in leak detection does not:

  • Provides a complete stack trace for each leaked block, including source file and line number information when available.
  • Provides complete data dumps (in hex and ASCII) of leaked blocks.
  • Customizable level of detail in the memory leak report via preprocessor macro definitions. Using macros allows you to make these customizations via your project's build settings, instead of having to modify any source code.

Okay, but how is Visual Leak Detector better than the dozens of other leak detectors here?

  • Visual Leak Detector is now packaged as an easy-to-use library. Just copy the library to the appropriate directory and include a single header.
  • In addition to providing stack traces with source files, line numbers and function names, Visual Leak Detector also provides data dumps.
  • It works with both C and C++ programs (compatible with both malloc/free and new/delete).
  • It is well documented, so it is easy to modify it to suit your needs if you so desire.

In addition to the features mentioned, it also provides most of the "standard" leak detection features. A memory leak report is dumped to the debug output window. From there you can see a summary of each leak detected and double-clicking a source file/line number in the debug output window will take you to that file and line in the editor.

How To Use Visual Leak Detector

Earlier versions of Visual Leak Detector (VLD) had a design that required absolutely no modification of the source files being debugged. But to acheive this, VLD had to be compiled into your program from source. It turned out that building VLD from source was, for most people, the hardest part about using it.

So to make life easier, VLD is now packaged as a library. This means that there is no longer a need to build VLD from source. But it also means that there is now a single header file that needs to be included in one of your own source files that tells your program to link with the VLD library. But beyond that, you don't need to make any other changes to your sources. In the end, this is a much easier way to use VLD because it eliminates all of the complexity involved with building VLD from source.

To use VLD with your project, follow these simple steps:

  1. Copy the VLD library (*.lib) files to your Visual C++ installation's "lib" subdirectory.
  2. Copy the VLD header (vld.h) file to your Visual C++ installation's "include" subdirectory.
  3. In one of your source files -- preferably the one with your program's main entry point -- add the line #include . It's probably best to add this #include before any of the other #includes in your file, but is not absolutely necessary. In most cases, the specific order will not matter.
  4. Windows 2000 users will also need to copy dbghelp.dll to the directory where the executable being debugged resides. This would also apply to users of earlier versions of Windows, but I can't guarantee that VLD even works on versions prior to Windows 2000.

When you build debug versions of your program, by including the vld.h header file, your program will be linked with VLD. When you run your program under the Visual C++ debugger, VLD will display a memory leak report in the debugger's output window when your program quits.

If memory leaks were detected, double-clicking on a source file/line number within the memory leak report will jump to that line of source in the editor window. In this way, you can easily navigate the code that led up to the memory allocation that resulted in a memory leak.

Configuring Visual Leak Detector

There are a few optional preprocessor macros that you can define to contol the level of detail provided in memory leak reports.

  • VLD_MAX_TRACE_FRAMES: By default, Visual Leak Detector will trace back as far as possible the call stack for each block that is allocated. Each frame traced adds additional overhead (in CPU time and memory use) to your debug executable. If you'd like to limit this overhead, you can define this macro to an integer value. The stack trace will stop when it has traced this number of frames. The frame count includes the "useless" frames which, by default, are not displayed in the debug output window (see VLD_SHOW_USELESS_FRAMES below). Usually, there will be about 5 or 6 "useless" frames at the beginning of the call stack. Keep this in mind when using this macro, or you may not see the number of frames you expect.
  • VLD_MAX_DATA_DUMP: Define this macro to an integer value to limit the amount of data displayed in memory block data dumps. When this number of bytes of data has been dumped, the dump will stop. This can be useful if any of the leaked blocks are very large and the debug output window becomes too cluttered. You can define this macro to 0 (zero) if you want to suppress the data dumps altogether.
  • VLD_SHOW_USELESS_FRAMES: By default, only "useful" frames are printed in the call stacks. Frames that are internal to the heap or Visual Leak Detector are not shown. Define this to force all frames of the call stacks to be printed. This macro might be useful if you need to debug Visual Leak Detector itself or if you want to customize it.

Defining these preprocessor macros is all you need to do to configure VLD with C++ programs. But if you are using VLD with a C program, in addition to defining these macros, you'll also need to place a call to VLDConfigure() somewhere in your program. It's best to place the call to VLDConfigure() as early in your program as possible.

How Visual Leak Detector Works

Probably the most important part of Visual Leak Detector (VLD) is the function allochook(). This function gets registered with the C runtime's debug heap as a callback function. Anytime a block of memory is allocated or freed, the debug heap will call this callback function. This is how VLD is able to keep track of allocated memory. Microsoft has provided a method for registering this type of callback function with the debug heap: _CrtSetAllocHook(). If you want to learn more about how this works, it is quite well documented in the MSDN Library. A global instance of class VisualLeakDetector is already created for you. When your program starts, this global object's constructor registers the callback function via _CrtSetAllocHook(), so that it is installed before any of your code runs*. To keep track of each allocated memory block, a simple STL map container is employed to map each block to the call stack that allocated it.

Though allochook() is critical to VLD's ability to track memory allocations, most of the heavy lifting is actually done in a couple of other functions: getstacktrace() and reportleaks(). Of the two, getstacktrace() is probably the most important, and probably also the trickiest to understand and properly implement.

If you're not familiar with assembly language or the organization of the stack, then getstacktrace() will likely be somewhat difficult to understand. In a nutshell, it makes use of Microsoft's StackWalk64() function to produce a stack trace. This function is part of the Debug Help Library which, if you're interested, you can read more about in the MSDN Library. VLD pushes the program counter from each level of the stack onto a simple STL vector container. Then, if leaks are detected, this vector is traversed to reproduce the desired stack trace.

After your program exits, the global instance of class VisualLeakDetector will be destroyed. The destructor calls the other important function, reportleaks(). This function is important because it translates the program counter addresses recorded during the stack walk into meaningful symbol names. It retrieves two pieces of information for each address: the name of the function containing that program address, and the source file and line number that generated the machine code at that address. These two pieces of information allow VLD to produce human-readable call stacks for the memory leak report. reportleaks() also obtains a pointer to the user-data section of the leaked memory block. Using that pointer, it is able to produce a formatted dump of the data contained in the memory block. Seeing the data stored in the block can sometimes be of help in isolating the source of a leak (more so than just a block number or memory address can).

Key Parts of the Source Explained

This is the VisualLeakDetector class constructor. Note the call to _CrtSetAllocHook(). This is a key part of the program which register's our callback function (allochook()) with the debug heap. The call to linkdebughelplibrary() performs an explicit dynamic link with the Debug Help Library (dbghelp.dll). Because VLD is itself a library, implicitly linking with the Debug Help Library through the import library dbghelp.lib is undesirable, because that would make the VLD library dependent on dbghelp.lib, which will not be present on many Windows computers.

// Constructor - Installs our allocation hook function so that the C runtime's
// debug heap manager will call our hook function for every heap request.
//
VisualLeakDetector::VisualLeakDetector ()
{
static bool already_instantiated = false;

// Disallow more than one instance of VisualLeakDetector. If this code is
// asserting, then you've instantiated a second instance. Only one instance
// should be created and it is already done for you (see above).
assert(!already_instantiated);
already_instantiated = true;

// Initialize private data.
m_maxdatadump = 0xffffffff;
m_maxtraceframes = 0xffffffff;
m_process = GetCurrentProcess();
m_showuselessframes = false;
#ifndef _MT
m_thread = GetCurrentThread();
#endif // _MT

if (linkdebughelplibrary()) {
// Register our allocation hook function with the debug heap.
m_poldhook = _CrtSetAllocHook(allochook);
_RPT0(_CRT_WARN, "Visual Leak Detector Version "VLD_VERSION" installed.\n");
m_installed = true;
}
else {
_RPT0(_CRT_WARN, "Visual Leak Detector IS NOT installed!\n");
m_installed = false;
}
}

Here we see the code responsible for recording the call stack for each allocated block. This is perhaps the trickiest part of the entire program. This function relies on the architecture-specific function getprogramcounterintelx86()for retrieving the EIP register on Intel x86 processors. But the StackWalk64() function is really at the heart of this function. It is where the true work is done of tracing back through the stack and the program's machine code to find the calling function from each frame on the stack. Without StackWalk64(), this function would likely have to be a lot more complicated. pStackWalk64 is a pointer to the StackWalk64 function exported by dbghelp.dll. Likewise pSymFunctionTableAccess64 and pSymGetModuleBase64 are just pointers to the exported functions from dbghelp.dll.

The assembly code here is absolutely necessary. I've seen other examples similar to this in the past where GetThreadContext() is used to obtain the required register values. That method is totally unsafe, because GetThreadContext(), as its documentation clearly explains, may not be used to obtain a running thread's context. By definition, this means that if a thread wants to get it's own context using GetThreadContext(), it can't. Some other thread would have to obtain it while the target thread is suspended.

// getstacktrace - Traces the stack, starting from this function, as far
// back as possible. Populates the provided CallStack with one entry for each
// stack frame traced. Requires architecture-specific code for retrieving
// the current frame pointer and program counter.
//
// - callstack (OUT): Empty CallStack vector to be populated with entries from
// the stack trace. Each frame traced will push one entry onto the CallStack.
//
// Note:
//
// Frame pointer omission (FPO) optimization must be turned off so that the
// EBP register is guaranteed to contain the frame pointer. With FPO
// optimization turned on, EBP might hold some other value.
//
// Return Value:
//
// None.
//
#pragma optimize ("y", off)
void VisualLeakDetector::getstacktrace (CallStack& callstack)
{
DWORD architecture;
CONTEXT context;
unsigned int count = 0;
unsigned long framepointer;
STACKFRAME64 frame;
unsigned long programcounter;

// Get the required values for initialization of the STACKFRAME64 structure
// to be passed to StackWalk64(). Required fields are AddrPC and AddrFrame.
#ifdef _M_IX86
architecture = IMAGE_FILE_MACHINE_I386;
programcounter = getprogramcounterintelx86();
__asm mov [framepointer], ebp // Get the frame pointer (aka base pointer)
#else
// If you want to retarget Visual Leak Detector to another processor
// architecture then you'll need to provide architecture-specific code to
// retrieve the current frame pointer and program counter in order to initialize
// the STACKFRAME64 structure below.
#error "Visual Leak Detector is not supported on this architecture."
#endif // _M_IX86

// Initialize the STACKFRAME64 structure.
memset(&frame, 0x0, sizeof(frame));
frame.AddrPC.Offset = programcounter;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Offset = framepointer;
frame.AddrFrame.Mode = AddrModeFlat;

// Walk the stack.
while (count < m_maxtraceframes) {
count++;
if (!pStackWalk64(architecture, m_process, m_thread, &frame, &context,
NULL, pSymFunctionTableAccess64, pSymGetModuleBase64, NULL)) {
// Couldn't trace back through any more frames.
break;
}
if (frame.AddrFrame.Offset == 0) {
// End of stack.
break;
}

// Push this frame's program counter onto the provided CallStack.
callstack.push_back(frame.AddrPC.Offset);
}
}
#pragma optimize ("y", on)

And here is the function that retrieves the EIP register. This has to be done as a separate function because there is no way for software to directly read the EIP register. But the same value can be obtained by making a function call, and then from the called function getting the return address (which will be the exact same value as the EIP register from where the function was called).

// getprogramcounterix86 - Helper function that retrieves the program counter
// (aka the EIP register) for getstacktrace() on Intel x86 architecture. There
// is no way for software to directly read the EIP register. But it's value
// can be obtained by calling into a function (in our case, this function) and
// then retrieving the return address, which will be the program counter from
// where the function was called.
//
// Notes:
//
// a) Frame pointer omission (FPO) optimization must be turned off so that
// the EBP register is guaranteed to contain the frame pointer. With FPO
// optimization turned on, EBP might hold some other value.
//
// b) Inlining of this function must be disabled. The whole purpose of this
// function's existence depends upon it being a *called* function.
//
// Return Value:
//
// Returns the return address of the current stack frame.
//
#ifdef _M_IX86
#pragma optimize ("y", off)
#pragma auto_inline(off)
unsigned long VisualLeakDetector::getprogramcounterintelx86 ()
{
unsigned long programcounter;

__asm mov eax, [ebp + 4] // Get the return address out of the current stack frame
__asm mov [programcounter], eax // Put the return address into the variable we'll return

return programcounter;
}
#pragma auto_inline(on)
#pragma optimize ("y", on)
#endif // _M_IX86

Next, we have a snippet that shows how the symbols are retrieved for the addresses obtained during the stack walk. Note that this code is only run if memory leaks are detected. This avoids having to do symbol lookups on-the-fly while the program is running, which would add considerable additional overhead. Not to mention that it just doesn't make sense to store (large) symbol names for later retrieval when you can store (small) addresses instead.

Here again, pSymSetOptions, pSymInitialize, pSymGetLineFromAddr64, and pSymFromAddr are all pointers to the functions exported by dbghelp.dll.

    ...

IMAGEHLP_LINE64 sourceinfo;
#define MAXSYMBOLNAMELENGTH 256
#define SYMBOLBUFFERSIZE (sizeof(SYMBOL_INFO) + (MAXSYMBOLNAMELENGTH * sizeof(TCHAR)) - 1)
unsigned char symbolbuffer [SYMBOLBUFFERSIZE];

// Initialize structures passed to the symbol handler.
pfunctioninfo = (SYMBOL_INFO*)symbolbuffer;
memset(pfunctioninfo, 0x0, SYMBOLBUFFERSIZE);
pfunctioninfo->SizeOfStruct = sizeof(SYMBOL_INFO);
pfunctioninfo->MaxNameLen = MAXSYMBOLNAMELENGTH;
memset(&sourceinfo, 0x0, sizeof(IMAGEHLP_LINE64));
sourceinfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);

// Initialize the symbol handler. We use it for obtaining source file/line
// number information and function names for the memory leak report.
path = buildsymbolsearchpath();
pSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
if (!pSymInitialize(m_process, (char*)path.c_str(), TRUE)) {
_RPT1(_CRT_WARN,
"WARNING: Visual Leak Detector: The symbol handler failed to initialize (error=%d).\n"
" Stack traces will probably not be available for leaked blocks.\n",
GetLastError());
}

...

for (itstack = callstack.begin(); itstack != callstack.end(); itstack++) {
// Try to get the source file and line number associated with
// this program counter address.
if (pSymGetLineFromAddr64(m_process, *itstack, &displacement, &sourceinfo)) {
// Unless m_showuselessframes has been toggled, don't show
// frames that are internal to the heap or Visual Leak
// Detector. There is virtually no situation where they
// would be useful for finding the source of the leak.
if (!m_showuselessframes) {
if (strstr(sourceinfo.FileName, "afxmem.cpp") ||
strstr(sourceinfo.FileName, "dbgheap.c") ||
strstr(sourceinfo.FileName, "new.cpp") ||
strstr(sourceinfo.FileName, "vld.cpp")) {
continue;
}
}
}

// Try to get the name of the function containing this program
// counter address.
if (pSymFromAddr(m_process, *itstack, &displacement64, pfunctioninfo)) {
functionname = pfunctioninfo->Name;
}
else {
functionname = "(Function name unavailable)";
}

// Display the current stack frame's information.
if (sourceinfo.FileName) {
_RPT3(_CRT_WARN,
" %s (%d): %s\n",
sourceinfo.FileName,
sourceinfo.LineNumber,
functionname.c_str());
}
else {
_RPT1(_CRT_WARN,
" 0x%08X (File and line number not available): ",
*itstack);
_RPT1(_CRT_WARN, "%s\n", functionname.c_str());
}
}

...

Finally, here is a short bit of code demonstrating how the global instance of the VisualLeakDetector class gets constructed before any user global objects. This is achieved by using the #pragma init_seg(lib) directive.

// The one and ONLY VisualLeakDetector object instance. This is placed in the
// "library" initialization area, so that it gets constructed just afer C
// runtime initialization, but before any user global objects are constructed.
// Also, disable the warning about us using the "library" initialization area.
#pragma warning(disable:4073)
#pragma init_seg(lib)
VisualLeakDetector visualleakdetector;

Building Visual Leak Detector From Source

Because Visual Leak Detector is open source, the library can be built from source if you want to tweak it to your liking. The hardest part about building the VLD libraries from source is getting your build environment correctly set up. But if you follow these instructions carefully, the process should be fairly painless.
  1. Visual Leak Detector depends on the Debug Help Library (dbghelp.dll) version 5.1 or later. Various versions of this DLL are shipped with the Windows operating systems. The latest version is always included with Debugging Tools for Windows. Version 6.3 of the DLL is included with VLD.
    • Windows XP users should already have a new enough version of dbghelp.dll in WINDOWS\system32. So, if you're running Windows XP, you don't need to do anything with the dbghelp.dll included with VLD.
    • Windows 2000 shipped with an older version of dbghelp.dll. To build VLD on Windows 2000, you must use a newer version (5.1 or newer). The best way is to use the copy of dbghelp.dll included with VLD (version 6.3). Place the included copy of the DLL in the directory where the executable you are debugging resides.
    • Windows Server 2003... I don't know about. But I'm fairly certain it ships with a newer version of dbghelp.dll, so Windows 2003 users probably don't need to do anything with the DLL.
  2. The Debug Help Library header file (dbghelp.h) won't compile unless you have a recent Platform SDK installed. I recommend installing the Windows XP SP2 Platform SDK. This SDK is compatible with Windows XP, Windows 2000, and Windows Server 2003. If you're debugging an application for Windows Server 2003, the Windows Server 2003 Platform SDK will probably work as well, but I haven't tried it myself so I can't guarantee it will work. Both of these SDKs can be downloaded from Platform SDK Update.
  3. Once you have the Platform SDK installed, you'll need to make Visual C++ aware of where it can find the updated headers and libraries. To do this, add the "include" and "lib" subdirectories from the Platform SDK installation directory to the include and library search paths in Visual C++:
    • Visual C++ 7: Go to Project Properties -> C/C++ -> General -> Additional Include Directories and add the "include" subdirectory from the Platform SDK. Make sure it's at the top of the list. Do the same for the "lib" subdirectory, but add it to Library Directories instead of Include Directories.
    • Visual C++ 6: Go to Tools -> Options -> Directories. Select "Include files" from the "Show Directories For" drop-down menu. Add the "include" subdirectory from the Platform SDK. Make sure it's at the top of the list. Do the same for the "lib" subdirectory, but add it to the "Library files" list instead of the "Include files" list.
  4. VLD also depends on a couple of other header files (dbgint.h and mtdll.h) that will only be installed if you elected to install the CRT source files when you installed Visual C++. If you didn't install the CRT sources, you'll need to re-run the Visual C++ installer and install them. If you are not sure whether you installed the CRT sources when you installed Visual C++, check to see if dbgint.h and mtdll.h exist in the CRT\src subdirectory of your Visual C++ installation. If those files are missing, or you don't have a CRT\src directory, then chances are you need to re-install Visual C++ with the CRT sources selected.

Once you've completed all of the above steps, your build environment should be ready. To build VLD, just open the vld.dsp project and do a batch build to build all six of the configurations:

  • The three debug configurations are for building versions of the library that have debugging information so that VLD itself can be conveniently debugged.
  • The three release configurations build the library for use in debugging other programs. There are three configurations each: one for each method of linking with the C runtime library (single-threaded, multithreaded, and DLL). When linking the VLD library against a program, the vld.h header file detects how the program is linking to the C runtime library and selects the appropriate VLD library from the three possible choices.

Note that when VLD is built, it always links against debug versions of the C runtime libraries -- even the release builds of VLD do. This is a requirement. VLD depends on features of the heap that are only present in debug versions of the C runtime.

Miscellaneous Notes On Building From Source

VLD can also be directly linked to your program as a regular object (.obj) file if you want. Just add vld.cpp to an existing project. If your build environment is setup correctly, then vld.obj should effortlessly link with the program. I don't think there's any advantage to doing it this way, versus linking with the library.

Known Bugs

These are known bugs in the latest release (currently 0.9d):

  • If the preprocessor macro VLD_MAX_DATA_DUMP is defined as 0 (zero), then VLD will get stuck in an infinite loop, repeatedly printing the same information while attempting to display the memory leak report in the debugger's output window. Define VLD_MAX_DATA_DUMP to a minimum of 1 to work around this issue.

Solutions To Common Problems

Here's a list of problems you might run into and potential solutions:
  • "the procedure entry point SymFromAddr could not be located in the dynamic link library dbghelp.dll" when running a program with VLD
    This typically only happens on Windows 2000 clients. It will happen if the Debug Help Library is out-of-date. Copy the included version of dbghelp.dll (version 6.3) to the directory where the executable you are debugging resides. If dbghelp.dll is missing for some reason, you can get it by installing Debugging Tools for Windows. I recommend installing version 6.3.
  • Compile Error C1083: Cannot open include file: 'dbgint.h': No such file or directory, when building VLD from source
    This will happen if the CRT source files are not installed. These are an optional part of the installation when you first install Visual C++. Re-run the Visual C++ installation, if needed, to install them. If the CRT sources are already installed, make sure the CRT\src subdirectory of the Visual C++ installation directory is in Visual C++'s include search path.
  • Compile Error C2059: syntax error : '...', or a lot of other compile errors in dbghelp.h, while building VLD from source
    Visual C++ is including the wrong copy of dbghelp.h. Be sure that the include search path points to the Platform SDK "include" subdirectory, not the "sdk\inc" subdirectory of "Debugging Tools for Windows".

Credits

  • Credit for the idea of how to make VLD's global class VisualLeakDetector object get constucted before any other user global objects goes to cmk. Thanks cmk!
  • Thanks to Nitrogenycs (aka Matthias) for discovering the VLD_MAX_DATA_DUMP infinite loop bug.
  • Thanks to hsvcs (aka Holger) for discovering the VLD_MAX_DATA_DUMP compilation bug.
  • Thanks to Don Clugston for pointing out to me that people sometimes do build optimized debug executables, and that I need to watch out for that.

References

Here are some links to useful related articles and resources:

Caveats

If you were paying close attention when I was explaining how Visual Leak Detector works, you noticed an asterisk where I was discussing how the global VisualLeakDetector object is instantiated. Well, there is in fact some fine print and here it is:

* In order to be successful at detecting leaks, VLD's code must run before any of the code being debugged. Most often this will happen without a hitch. However, there are some rare instances where this might not happen: if any global objects in the program have been placed in the "compiler" or "library" initialization areas. However, user global objects are never placed in these areas by default. They must be manually placed there by using the "#pragma init_seg(...)" directive. As long as you are not using this directive then VLD will not have any problem running before your code. If you are using it, then you should take whatever measures are necessary to ensure that objects from the VLD library are constructed before your first global object is constructed. If this situation applies to you, but you are not concerned about the possibility of memory leaks in your global objects' constructors, then it will not be a problem if your global objects are consructed before VLD's objects.

History

30 March 2005 - Uploaded version 0.9d which is the first release of VLD in library form. Packaged as a library, VLD can now be used to debug other programs without having to build VLD from source.

17 March 2005 - Uploaded version 0.9c which includes a minor bug fix. Problems fixed in version 0.9c:

  • Compile error, "error C2039: 'size' : is not a member of '_CrtMemBlockHeader'" occurs at line 644 of vld.cpp when building VLD with the VLD_MAX_DATA_DUMP preprocessor macro defined.

15 March 2005 - I've uploaded version 0.9b of the source and example projects. Problems fixed in version 0.9b are:

  • VLD fails to detect memory leaks in class constructors if the objects constructed are global objects.
  • If a debug executable is built with certain compiler optimizations turned on, specifically frame pointer omission optimization or automatic inlining, then theoretically VLD may produce incomplete or inaccurate stack traces or might fail to produce stack traces altogether.

About Dan Moulding


In real life I'm a firmware engineer. I mostly do C and assembly programming on obscure proprietary hardware. But I started my programming career doing a lot of C++. So, occassionally in my free time I enjoy dabbling in my own Windows programming projects with Visual C++ to keep my C++ skills from rotting away completely.

I also like to keep abreast of the GNU/Linux scene because, well let's face it, Windows isn't everything. I've recently found Cygwin to be a good way of getting the best of both worlds.

Click here to view Dan Moulding's online profile.


Other popular articles:

댓글

이 블로그의 인기 게시물

oradiag_??? 로그 생성안되게 하는 방법

cx_Oracle이나 oci로 개발된 프로그램을 사용하다 보면 $HOME에 orgdiag_사용자계정으로 로그가 대량으로 저장되는 경우가 발생합니다. 이런 경우에 로그가 남지 않도록 하던지 아님 다른 경로에 저장하는 방법은  아래와 같은 방법으로 처리할 수 있습니다. 로그 안남기는 방법은. 환경변수에 추가 export TNS_ADMIN=/home/eek/conf/ 해당경로에 sqlnet.ora파일 생성해서 DIAG_ADR_ENABLED=off TRACE_LEVEL_CLIENT=off LOG_FILE_CLIENT=/dev/null 설정값을 추가하면 로그 파일이 생성되지 않음. 자세한 설정 정보는 http://docs.oracle.com/cd/B28359_01/network.111/b28317/sqlnet.htm#BIIDEAFI 참고하세요. 끝.

Jakarta Tomcat을 갖춘 개발 환경으로서의 Eclipse

Jakarta Tomcat을 갖춘 개발 환경으로서의 Eclipse 목차: 왜 Eclipse와 Tomcat 인가? 컴포넌트 다운로드 설치 모든 컴포넌트의 압축 풀기 Tomcat 플러그인을 Eclipse/플러그인 디렉토리에 복사하기 SDK 설치 설정 SDK JRE를 Eclipse용 디폴트 JRE로 설정하기 Tomcat 선택 옵션에서 Tomcat Home 변수 설정하기 Tomcat과 Eclipse를 함께 테스트하기 새로운 Tomcat 프로젝트 만들기 테스트용 JSP 파일 만들기 Sysdeo 플러그인을 사용하여 Tomcat 시작하기 브라우저를 시작하고 index.jsp 파일 보기 참고자료 필자소개 기사에 대한 평가 Subscriptions: dW newsletters Eclipse와 Tomcat 통합의 빠른 길 난이도 : 초급 Geoffrey R. Duck Software Developer, IBM 2004년 5월 Eclipse 를 자바 개발 환경으로 사용하는 것은 대단한 일이다. Eclipse Tomcat 플러그인을 사용하면 자바와 웹 개발 프로젝트를 더욱 훌륭하게 조직화하고 통합할 수 있다. 이 글에서는 Eclipse, Jakarta Tomcat, Eclipse Tomcat 시작 플러그인의 설치부터 단계별로 소개하겠다. 왜 Eclipse와 Tomcat 인가? 나는 초창기부터 Eclipse로 개발해왔고 나의 자바 개발 역사에 발생한 최고의 사건들 중 하나이다. 오직 vi와 JDK 만을 사용하여 리눅스에서 자바 프로그래밍을 해왔던 경험에서 볼 때 자바 프로그래밍과 디버깅은 지루한 작업이다. 이제 Eclipse 덕분