1. Improve the stability of the Delphi Program
Software quality is the lifeline of a product and the key to the happiness of software developers. Every day, many programmers work overtime due to software quality, it is often the case that the newly released program keeps releasing the patch package. Software Quality is like a nightmare. It keeps catching up with programmers, making them exhausted, and even spreading a sentence in the programmer: "Life is endless, there are more than bugs ".
Today, we are not going to explore bugs that can be reproduced. We do not define bugs that can be reproduced as bugs, and only bugs that cannot be reproduced will make you restless. I used to develop server software in a company. As a result, the program was unstable and some non-reproducible errors caused us to constantly send people to stare at the server. Instability is like a evil ghost, which lingers in our hearts all day long. The continuous urging of leaders and complaints from customers make our project team exhausted and bitter. I have found countless bugs that cannot be reproduced, mainly due to the following eight reasons:
1. The variable is not initialized;
2. The function return value is not initialized;
3. Compilation optimization errors;
4. Function recursion;
5. Message re-import;
6. Wild pointer;
7. Memory leakage;
8. Concurrency;
You will find some minor problems, so programmers must develop good habits in daily development.
2. Variable not initialized
By default, Delphi initializes global variables and class members. Other variables in the function body are not initialized. Therefore, remember to initialize some variables used for judgment or loop, in addition, the enumeration type and applied memory must be initialized. pchar must be added with #0 at the end. For example, the following returned results may contain garbled characters.
Function temppath: string;
Begin
Setlength (result, gettemppath (0, pchar (result )));
Gettemppath (length (result), pchar (result ));
Result: = pchar (result );
End;
The correct method should be
Function temppath: string;
Begin
Setlength (result, gettemppath (0, pchar (result )));
Zeromemory (pchar (result), length (result ));
Gettemppath (length (result), pchar (result ));
Result: = pchar (result );
End;
This program is typical when applying for memory, pchar is not initialized, so it may end with a random value, but with zeromemory, the end is assigned #0.
3. The function return value is not initialized.
In Delphi, exit functions use exit functions. When many functions exit, they do not initialize the function return value. Therefore, the return value of a function is a random value, cause non-reproducible errors to the program running. For example, the execution result of the following program will surprise you.
Procedure notinitresult;
VaR
I: integer;
Function getstring (avalue: integer): string;
Begin
If avalue = 0 then
Result: = 'true ';
End;
Begin
For I: =-1 to 1 do
Begin
Showmessage (getstring (I ));
End;
End;
The running result is '', 'true', and 'true'. The correct statement is as follows:
Procedure notinitresult;
VaR
I: integer;
Function getstring (avalue: integer): string;
Begin
If avalue = 0 then
Result: = 'true'
Else
Result: = '';
End;
Begin
For I: =-1 to 1 do
Begin
Showmessage (getstring (I ));
End;
End;
Therefore, the IF or case statement must be assigned an initial value. The preceding function can be written as follows:
Function getstring (avalue: integer): string;
Begin
Result: = '';
If avalue = 0 then
Result: = 'true ';
End;
Function getstring (avalue: integer): string;
Begin
Case avalue
0: Result: = 'true ';
Else result: = '';
End;
End;
Iv. Errors Caused by compilation Optimization
The current compiler will optimize some code that can not be executed during code compilation. For example, Boolean optimization is the most common one. The following example shows the problem.
Procedure tform1.btn1click (Sender: tobject );
VaR
S: string;
Begin
If gettrue or getvalue1 (s) then
Showmessage ('hello' + S );
End;
Procedure tform1.btn2click (Sender: tobject );
VaR
S: string;
Begin
If gettrue or getvalue2 (s) then
Showmessage ('hello' + S );
End;
Function tform1.gettrue: Boolean;
Begin
Result: = true;
End;
Function tform1.getvalue1 (var s: string): variant;
Begin
Result: = true;
S: = 'World ';
End;
Function tform1.getvalue2 (var s: string): Boolean;
Begin
Result: = true;
S: = 'World ';
End;
You will find that when you click btn1, the result is "Hello word", but when you click btn2, it is "hello"
V. Function Recursion
If a recursive function exists, pay special attention to whether the function execution will exit normally. If the function is executed continuously, all the call stacks of the program will be finished, causing the program to terminate abnormally, as shown in the following example: with a single btn1, the program will die silently without logs. This kind of code requires special attention when running in the service mode, because your service runs unattended, in this case, your service will exit directly without any prompt, and you cannot find any problems.
Procedure tform1.btn1click (Sender: tobject );
Procedure recursive;
Begin
Recursive;
End;
Begin
Recursive;
End;
Vi. Message re-import
The concept of message re-import is that there is a message execution process that has not been executed, and the same message enters the same function for processing. The major reason for message re-entry is that application is called in many software programs. processmessage is used to update the interface. If an operation takes a long time, you can change it to a thread for execution or do not call the application. processmessage function. For example, the following function can easily cause message re-entry.
Procedure tform1.btn1click (Sender: tobject );
VaR
I: integer;
Begin
For I: = 0 to 10000000 do
Begin
Application. processmessages;
End;
End;
If you must use application. processmessage is used to update the interface. You should ensure that the message is not delivered for the second time during function execution. In this example, you can disable the status of btn1 to prevent message re-entry, the correct statement is as follows:
Procedure tform1.btn1click (Sender: tobject );
VaR
I: integer;
Begin
Btn1.enabled: = false;
For I: = 0 to 10000000 do
Begin
Application. processmessages;
End;
Btn1.enabled: = true;
End;
In addition, when sending a message, pay special attention to the difference between sendmessage and postmessage. sendmessage is sent after the message is processed and then returned. postmessage is delivered to the Message Buffer Pool for queuing, return immediately (at this time, the message may not be processed), and the message needs to be processed when it is its turn.
VII. Wild pointer
The wild pointer cannot be detected during compilation. It only appears during runtime. The most common error of the wild pointer is the access violation error (av error ), this error occurs because the physical memory you point to is unavailable. The occurrence of the wild pointer is mainly caused by the following four reasons: 1. the pointer variable is not initialized; 2. the pointer is used again after being free or dispose; the pointer operation is beyond the range of the variable; 4. The string address is used to determine whether the string has been allocated memory.
When judging whether the pointer is null, the Code determines whether the pointer value is between 0x00000000 and 0x0000ffff. If the if statement is used, the code can determine whether the pointer value is null or not, the pointer is considered valid. Therefore, after the application or release, the pointer points to a random address, so the if statement cannot be used. In Delphi, if you set the pointer to nil and translate it into assembly code, it is an exception or a bit. You can open the CPU window to view it, for example:
FM: = nil; the generated assembly is: XOR eax, which sets the pointer to 0x00000000.
8. Memory leakage
Memory leakage means that the software does not release the applied memory space during the running process, resulting in a larger memory usage. In the end, the program crashes abnormally without leaving any marks at this time, no system logs are available. Memory leakage can be divided into two types: one is that the program moves together, and then occupies the memory, will not grow with the program running; the other is that with the program running continues to grow; if it is the first one, you can let it go, for the other two types of data, you must check them carefully. fastmm is recommended for the tool, and select the project attribute compiler-> use DEBUG dcus and linker-> map file-> detailed of Delphi, in this way, fastmm can extract the call stack and map address of the applied memory, which is very helpful for finding Memory leakage. Generally, you can consider the following aspects:
1. When using dispose to release memory, add the definition information. If no definition information is added, some pointers or strings cannot be released, and internal pointers should be released before the struct has a pointer;
2. When using freemem or freememory to release the memory, you do not need to increase the small information because the Delphi memory manager knows the pointer size information;
3. The override function must be inherited to release the memory applied by the parent class;
4. Ensure that the applied memory is released. You can use try... Finally... End to ensure the memory is released, but this code style should not be try... Apply for memory... Finally... Release memory... End;
5. Ensure that the system kernel object is disabled;
6. If the requested pointer is allocated space in some cases, remember to initialize it to nil. When releasing the pointer, determine whether it is null, because releasing the NULL pointer will also cause memory leakage;
7. in addition, postmessage may also cause memory leakage. In this case, the structure is sent through postmessage, and the memory is released in the message processing function. If postmessage is frequently called, the message processing cycle is too busy, some messages will be lost, resulting in Memory leakage. The default Windows message queue length is 4000. If there are 4000 message queues, you can use postmessage to deliver messages, and the messages will be lost, the requested struct cannot be released, causing memory leakage;
9. Concurrency
If the program involves multiple threads and there is a cooperative relationship between threads, if the thread crashes at this time, it is necessary to check thread synchronization. This type of problem is generally difficult to query and requires a good understanding of the Code Execution Process, this is a type of problem that is hard to handle. You can use a few third-party tools, such as procexp.exe, to view the status of each thread. If a thread stops, you can locate the problem through the map address and call stack. For example, the Excel thread status is as follows:
10. Some effective suggestions
To address these problems, what should we pay attention to during daily development? below are some suggestions I have given:
1. Exploring requirements, understanding the deeper the requirements, the lighter the quality and architecture of code writing, and greatly improved readability and maintainability;
2. Test-driven development;
3. Good code style and good coding habits have greatly improved the software quality;
4. variables (pointers and arrays) should be initialized in time after they are created;
5. Check whether the initial value and default value of the variable are incorrect or the accuracy is insufficient;
6. Make good use of As and is for type conversion;
7. Check whether the variable overflow or overflow exceeded the array;
8. Check for I/O errors. I/O does not always return true;
9. The data structure is sufficient. Do not design a comprehensive and flexible data structure;
10. Poor code. Don't think about changing the code and making it available. You should rewrite the code, because it is very likely that the hoist will trigger the crash;
11. Take every alert for program compilation seriously and write the code without warning;
12. Adding const to parameters that do not need to be modified not only improves efficiency, but also enhances security;