📄 debugging.html
字号:
<OL><LI> Building the collector with <TT>-DKEEP_BACK_PTRS</tt>,<LI> Preferably using debugging allocation (defining <TT>GC_DEBUG</tt>before including <TT>gc.h</tt> and allocating with <TT>GC_MALLOC</tt>),so that objects will be identified by their allocation site,<LI> Running the application long enough sothat most of the heap is composed of "leaked" memory, and<LI> Then calling <TT>GC_generate_random_backtrace()</tt> from backptr.ha few times to determine why some randomly sampled objects in the heap arebeing retained.</ol><P>The same technique can often be used to identify problems with falsepointers, by noting whether the reference chains printed by<TT>GC_generate_random_backtrace()</tt> involve any misidentified pointers.An alternate technique is to build the collector with<TT>-DPRINT_BLACK_LIST</tt> which will cause it to report values thatare almost, but not quite, look like heap pointers. It is very likely thatactual false pointers will come from similar sources.<P>In the unlikely case that false pointers are an issue, it can usuallybe resolved using one or more of the following techniques:<OL><LI> Use <TT>GC_malloc_atomic</tt> for objects containing no pointers.This is especially important for large arrays containing compressed data,pseudo-random numbers, and the like. It is also likely to improve GCperformance, perhaps drastically so if the application is paging.<LI> If you allocate large objects containing onlyone or two pointers at the beginning, either try the typed allocationprimitives is <TT>gc_typed.h</tt>, or separate out the pointerfree component.<LI> Consider using <TT>GC_malloc_ignore_off_page()</tt>to allocate large objects. (See <TT>gc.h</tt> and above for details.Large means > 100K in most environments.)<LI> If your heap size is larger than 100MB or so, build the collector with-DLARGE_CONFIG. This allows the collector to keep more precise black-listinformation.<LI> If you are using heaps close to, or larger than, a gigabyte on a 32-bitmachine, you may want to consider moving to a platform with 64-bit pointers.This is very likely to resolve any false pointer issues.</ol><H2>Prematurely Reclaimed Objects</h2>The usual symptom of this is a segmentation fault, or an obviously overwrittenvalue in a heap object. This should, of course, be impossible. In practice,it may happen for reasons like the following:<OL><LI> The collector did not intercept the creation of threads correctly ina multithreaded application, <I>e.g.</i> because the client called<TT>pthread_create</tt> without including <TT>gc.h</tt>, which redefines it.<LI> The last pointer to an object in the garbage collected heap was storedsomewhere were the collector couldn't see it, <I>e.g.</i> in anobject allocated with system <TT>malloc</tt>, in certain types of<TT>mmap</tt>ed files,or in some data structure visible only to the OS. (On some platforms,thread-local storage is one of these.)<LI> The last pointer to an object was somehow disguised, <I>e.g.</i> byXORing it with another pointer.<LI> Incorrect use of <TT>GC_malloc_atomic</tt> or typed allocation.<LI> An incorrect <TT>GC_free</tt> call.<LI> The client program overwrote an internal garbage collector data structure.<LI> A garbage collector bug.<LI> (Empirically less likely than any of the above.) A compiler optimizationthat disguised the last pointer.</ol>The following relatively simple techniques should be tried first to narrowdown the problem:<OL><LI> If you are using the incremental collector try turning it off fordebugging.<LI> If you are using shared libraries, try linking statically. If that works,ensure that DYNAMIC_LOADING is defined on your platform.<LI> Try to reproduce the problem with fully debuggable unoptimized code.This will eliminate the last possibility, as well as making debugging easier.<LI> Try replacing any suspect typed allocation and <TT>GC_malloc_atomic</tt>calls with calls to <TT>GC_malloc</tt>.<LI> Try removing any GC_free calls (<I>e.g.</i> with a suitable<TT>#define</tt>).<LI> Rebuild the collector with <TT>-DGC_ASSERTIONS</tt>.<LI> If the following works on your platform (i.e. if gctest still worksif you do this), try building the collector with<TT>-DREDIRECT_MALLOC=GC_malloc_uncollectable</tt>. This will causethe collector to scan memory allocated with malloc.</ol>If all else fails, you will have to attack this with a debugger.Suggested steps:<OL><LI> Call <TT>GC_dump()</tt> from the debugger around the time of the failure. Verifythat the collectors idea of the root set (i.e. static data regions whichit should scan for pointers) looks plausible. If not, i.e. if it doesn'tinclude some static variables, report this asa collector bug. Be sure to describe your platform precisely, since this sortof problem is nearly always very platform dependent.<LI> Especially if the failure is not deterministic, try to isolate it toa relatively small test case.<LI> Set a break point in <TT>GC_finish_collection</tt>. This is a goodpoint to examine what has been marked, i.e. found reachable, by thecollector.<LI> If the failure is deterministic, run the processup to the last collection before the failure.Note that the variable <TT>GC_gc_no</tt> counts collections and can be usedto set a conditional breakpoint in the right one. It is incremented justbefore the call to GC_finish_collection.If object <TT>p</tt> was prematurely recycled, it may be helpful tolook at <TT>*GC_find_header(p)</tt> at the failure point.The <TT>hb_last_reclaimed</tt> field will identify the collection numberduring which its block was last swept.<LI> Verify that the offending object still has its correct contents atthis point.Then call <TT>GC_is_marked(p)</tt> from the debugger to verify that theobject has not been marked, and is about to be reclaimed. Note that<TT>GC_is_marked(p)</tt> expects the real address of an object (theaddress of the debug header if there is one), and thus it maybe more appropriate to call <TT>GC_is_marked(GC_base(p))</tt>instead.<LI> Determine a path from a root, i.e. static variable, stack, orregister variable,to the reclaimed object. Call <TT>GC_is_marked(q)</tt> for each object<TT>q</tt> along the path, trying to locate the first unmarked object, say<TT>r</tt>.<LI> If <TT>r</tt> is pointed to by a static root,verify that the locationpointing to it is part of the root set printed by <TT>GC_dump()</tt>. If itis on the stack in the main (or only) thread, verify that<TT>GC_stackbottom</tt> is set correctly to the base of the stack. If it isin another thread stack, check the collector's thread data structure(<TT>GC_thread[]</tt> on several platforms) to make sure that stack boundsare set correctly.<LI> If <TT>r</tt> is pointed to by heap object <TT>s</tt>, check that thecollector's layout description for <TT>s</tt> is such that the pointer fieldwill be scanned. Call <TT>*GC_find_header(s)</tt> to look at the descriptorfor the heap chunk. The <TT>hb_descr</tt> field specifies the layoutof objects in that chunk. See gc_mark.h for the meaning of the descriptor.(If it's low order 2 bits are zero, then it is just the length of theobject prefix to be scanned. This form is always used for objects allocatedwith <TT>GC_malloc</tt> or <TT>GC_malloc_atomic</tt>.)<LI> If the failure is not deterministic, you may still be able to apply someof the above technique at the point of failure. But remember that objectsallocated since the last collection will not have been marked, even if thecollector is functioning properly. On some platforms, the collectorcan be configured to save call chains in objects for debugging.Enabling this feature will also cause it to save the call stack at thepoint of the last GC in GC_arrays._last_stack.<LI> When looking at GC internal data structures remember that a numberof <TT>GC_</tt><I>xxx</i> variables are really macro defined to<TT>GC_arrays._</tt><I>xxx</i>, so thatthe collector can avoid scanning them.</ol></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -