Article # 103, added by Geoworks, historical record
| first |
previous |
index |
next |
last |
Common programming mistakes of Geos neophytes
The following is a list of common mistakes commited by programmers who are new to Geos. 1. Not using EC code to catch errors Since Geos is multithreaded and unlocked memory blocks can be moved out from under a pointer, debugging memory scribbling is quite difficult. Become familiar with the EC routines that are available within Geos and use them liberally. When compiled as non-EC, these routines become empty stubs, so they won't impact the performance of the shipping version of your application. Related to this is stress testing your application with swat. By simply turning on many of the EC flags, you can find many bugs that would otherwise take days to find and duplicate. Here is a partial list of flags to set: General Memory +unlockMove Force unlocked blocks to move whenever possible. This causes memory leaks to be more consistently reproducable. +free Checks free blocks on the heap, which normally should contain 0xCC. If they don't, a fatal error is generated, and information about the previous blocks on the heap are dumped. The previous block is useful because often you will just be writing past the end of a block. Often you can just figure out what this previous block is, and then track the bug looking at the code. LMem (chunk, huge array, DB, etc.) +lmem Checks the lmem internal structures. If you find that an LMBH_handle (or another header field) is messed up, this is frequently useful for finding out when it is happening. +lmemMove Force lmem blocks to move whenever possible +high Simply increases the level of lmem checking. VMFiles +vm Checks VM file consistency +vmemDiscard Forces clean VM blocks to be discarded when unlocked +analVM Extensive VM memory checking Miscellaneous +graphics Checks gstrings and similar graphics stuff +segment Extensive segment checking +text Performs extra error checking on Text objects 2. Variables - Global variables, static variables and static strings take up space in dgroup. dgroup is a fixed block, so the bigger it gets the more grief it causes the memory manager. Move as much of statics and globals to object instance data or chunks in a data block. - Local variables are stored on the stack. This is only a bad thing when you have a local variable that is a huge structure or array (10s or 100s of bytes) because it could cause the stack to overflow. To reduce the size of variables on the stack, change the variable to a handle, optr, or ptr to a block or chunk that contains the structure. You can see the value of the stack pointer register for each frame on the stack by doing "backtrace -rsp" in swat. 3. Memory - Make sure to check for failed memory allocations or locks. (This can be determined by checking for NullHandle or null pointer.) - Don't allocate many memory blocks for small data structures. Each block takes up a global handle (of which there are usually only 3000 total) so don't create many blocks that each hold a small amount of data. This will eat away at the global handle table and can lead to crashes or other memory problems. - Don't let object resources get too big (break out into multiple resources) - In a method handler, pself can be invalidated after calling another message or when performing an LMem action on the obj block (oself). Make sure to re-dereference pself (with ObjDerefGen or ObjDerefVis) when using it after one of these invalidating actions. On the other hand, don't overkill by dereferencing after every routine call, too. (Note, this has changed for products after the N9000; see @self.) 4. Threads - Do not allow your application's ui thread to make calls to its process thread. This can result in deadlock because the process thread must occasionally make calls to the ui thread. - All objects in a Gen tree must be run by the same thread (usually the ui thread). 5. Files - Always check for successful file open/create. You can simply check if the returned FileHandle is NullHandle. If the file could not be opened or created and you try to access the file, it will crash the system. 6. UI and Generic object trees - The GenProcessClass has no instance data. NONE! It is a hybrid class that has no space allocated for instance data. If you try to give it instance data you are guaranteed to get memory scribbling errors. - Remember to use the neverSaved flag on ProcessClass @classdecl. Do not use this flag on objects that have instance data unless the object is marked ignoreDirty. - Don't over-use HINT_DEFAULT_FOCUS or HINT_DEFAULT_TARGET. Only one object at a given level in the gen tree can have the default focus or target. 7. Localization - The resource of chunks to be localized must be marked with the lmem flag. This can be done in the .gp file by adding "lmem" to the resource declaration. 8. Graphics - Difference between a GString and a GState. A GString is a data structure containing a sequence of graphics commands (see gstring.h). A GState contains information that keeps track of how to draw (the colors, scaling, current text font, etc.). A GState can contain a gstring. A GString cannot contain a GState. 9. Miscellaneous - For standard menus (like "File" or "Edit") use ATTR_GEN_INTERACTION_GROUP_TYPE = GIGT_????_MENU