Ich habe gerade einen Code in C++ geschrieben, der einige String-Manipulationen durchführt, aber als ich Valgrind überlief, zeigte es einige mögliche Speicherlecks. Beim Debuggen des Codes auf granularer Ebene habe ich ein einfaches C++-Programm geschrieben, das wie folgt aussieht:
#include<iostream>
#include<cstdlib>
using namespace std;
int main()
{
std::string myname("Is there any leaks");
exit(0);
}
und wenn ich valgrind darüber laufen lasse, bekomme ich:
==20943== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 26 from 1)
==20943== malloc/free: in use at exit: 360,645 bytes in 12,854 blocks.
==20943== malloc/free: 65,451 allocs, 52,597 frees, 2,186,968 bytes allocated.
==20943== For counts of detected errors, rerun with: -v
==20943== searching for pointers to 12,854 not-freed blocks.
==20943== checked 424,628 bytes.
==20943==
==20943== LEAK SUMMARY:
==20943== definitely lost: 0 bytes in 0 blocks.
==20943== possibly lost: 917 bytes in 6 blocks.
==20943== still reachable: 359,728 bytes in 12,848 blocks.
==20943== suppressed: 0 bytes in 0 blocks.
==20943== Reachable blocks (those to which a pointer was found) are not shown.
==20943== To see them, rerun with: --show-reachable=yes
Dann fiel mir auf, dass wir zwangsweise beendet wurden (was ich auch in meinem ursprünglichen C++-Code durchgeführt habe). Jetzt ist das Problem, dass ich das Programm beenden möchte, da mein vorheriger alter Code auf den Beendigungsstatus des neuen Codes wartet. Für zB binär wartet a.out auf den Exit-Status von b.out. Gibt es eine Möglichkeit, die Speicherlecks zu vermeiden, oder sollte ich mir wirklich Sorgen um die Speicherlecks machen, da das Programm zu diesem Zeitpunkt bereits beendet wird?
Dies wirft für mich auch eine andere Frage auf, ist ein solcher Code schädlich?
#include<stdio.h>
#include<cstdlib>
int main()
{
char *p=(char *)malloc(sizeof(char)*1000);
exit(0);
}
Wenn Sie einen Wert von main() zurückgeben, wird dieser Wert als Exit-Code Ihres Prozesses verwendet.
– Blechmann
27. Januar 2012 um 13:43 Uhr
Beachten Sie, dass Sie, wie valgrind richtig betont, in diesem Fall keine durchgesickerten Ressourcen haben. Es gibt nur ein paar Bytes zugewiesenen Speichers, die am Ende der Prozesslebensdauer noch erreichbar sind (auf die Sie noch einen Zeiger haben), aber das ist kein “Leck”.
– Frerich Raabe
27. Januar 2012 um 14:30 Uhr
Wie Sie sicherlich schon gelesen haben, “return exitcode;” ist viel besser als “exit(exitcode);” weil beide den Exit-Code-Status setzen. “return” erledigt die Bereinigung viel besser, während “exit” wahrscheinlich die Bereinigung umgeht.
– Stephen Quan
27. Januar 2012 um 14:37 Uhr
Haben Sie andere Tools außer Valgrind ausprobiert? Zum Beispiel Deleaker…
– MastAvalons
27. Januar 2012 um 20:52 Uhr
Beachten Sie, dass, wenn Sie einen Wert von zurückgeben main()es ist nicht wirklich ein int. Es wird in den gültigen Bereich von Exit-Codes konvertiert, d. h [0,256) (at least for Posix).
– moooeeeep
Feb 2, 2012 at 19:15
Use return 0; instead of exit(0); at the end of main. The use of exit circumvents the execution of the destructors.
As i mentioned i have to use exit because there is another program which is waiting for the exit status of this code. As program a.out is forking to run b.out something like calling C++ code when ur entire project is in C.
– Global Warrior
Jan 27, 2012 at 13:35
Using return 12 for example should return the same exit status to the operating system as exit(12) except it exits cleanly.
– jcoder
Jan 27, 2012 at 13:47
Just to clarify this, @Piyush – no, you don’t need to call exit. As JohnB says, the integer returned from main is used as the exit status – that’s what it’s there for.
– Useless
Jan 27, 2012 at 16:19
SigTerm
If you insist on using exit():
#include<iostream>
int main(){
{
std::string myname("Are there any leaks?");
}
exit(0);
}
Also, when you return from main the returned value becomes the application’s exit code. So if you want to pass an exit code, use return exitCode; in main() instead of exit.
Regarding that part:
This also raise another question for me, is such a code harmful?
Yes, because it is a BAD programming habit.
The OS will clean up any memory you failed to release, so as long as you haven’t managed to eat all system memory and the page file, you shouldn’t damage the OS.
However, writing sloppy/leaky code might turn into habit, so relying on the OS for cleaning up your mess is a bad idea.
The OS might clean up the memory, it’s not really guaranteed to do so (although most usually it will).
– TC1
Jan 27, 2012 at 14:49
Only a bad OS will not do that. Code is generally bad, unless proven otherwise.
– whitequark
Jan 27, 2012 at 15:39
Pro-Tip: Assume you are running on the Death Station 9000, a machine whose primary operating system allocates memory from the brains of kittens, and only puts it back if told to do so explicitly. Also, any instance of undefined behaviour will result in the destruction of the Earth.
– Kaz Dragon
Jan 27, 2012 at 15:47
@SigTerm It’s not about saving 3 lines of code. I appreciate how your advice applies to beginner programmers, but there comes a stage when you can do better than that. Why does Firefox take 30 seconds to shut down? Because it’s anal about cleaning up stuff that the OS could discard in milliseconds, and because current programming languages do not distinguish between optional resource deallocations and mandatory finalization such as flushing buffers. You propose we give up and just clean up everything. I propose we try a bit harder wherever we can.
– Roman Starkov
Feb 3, 2012 at 12:42
@SigTerm: For someone who doesn’t want to argue, you seem to be doing a lot of arguing 🙂
– Timwi
Feb 5, 2012 at 21:09
This also raise another question for me, is such a code harmful?
#include<stdio.h>
int main()
{
char *p=(char *)malloc(sizeof(char)*1000);
exit(0);
}
It’s not harmful on modern operating systems, because they will close all resources owned by a process automatically when the process ends.
However, it’s still bad practice, and might lead to subtle and hard to find errors when, over several years of maintenance, the code slowly changes until, on day, this does become harmful. I have worked in projects where some of the code was a decade old and I have learned a few lessons doing so, some of them rather harsh. Therefore, I would avoid writing such code, even if it currently doesn’t pose a problem.
But it can be harmful to maintainers of your code, who will have a harder time using tools like valgrind to track down legitimate problems.
– John Zwinck
Jan 27, 2012 at 13:30
@JohnZwinck Perhaps that’s an argument for why such tools should be improved. I mean they are currently preventing a legitimate technique: not spending time to do something that the OS can do far better.
– Roman Starkov
Feb 3, 2012 at 12:43
If you want, write a “fastTeardownWithoutMemoryDeallocation()” function in your C or C++ program. When and if it is called, then “forget” all your free() and delete calls and terminate. But writing classes which do not clean up in their destructors is bad, because you don’t know which classes are used temporarily at runtime and which are “permanent” until program shutdown.
– John Zwinck
Feb 4, 2012 at 1:09
In most cases, it’s worth cleaning up after yourself, for the many good reasons already given: better maintainability, better utility from checking tools and so on.
If there are other functional reasons to clean up, maybe your data is saved to a persistent store, then you have no choice – you must clean up (although you might want to reconsider your design).
In some cases however, it may be better to just exit and “leak”.
At the end of a program, your process is going to exit. When it does so, the operating system will recover any memory allocated by your program and in some cases it can do this much more quickly.
Consider a large linked list, where each node is dynamically allocated, and carries a substantial dynamically allocated structure. To clean this up you must visit each node and release each payload (which in turn may cause other complex structures to be walked).
You may end up performing millions of memory operations to run through such a structure.
The user wants to exit your program, and they sit there for 10s of seconds waiting for a bunch of junk processing to happen. They cannot possibly be interested in the result – they’re quitting the program after all.
If you let this “leak”, the operating system can reclaim the entire block of memory allocated to your process much more quickly. It doesn’t care about the structures and any object cleanup.
Ultimately you must understand what your tools are telling you, to be sure you’re using them properly.
To avoid the memory leak, return the status from main instead of calling exit. If you’re returning zero, you can omit the return statement if you like; the program will exit with a status of zero in that case.
This also raise another question for me, is such a code harmful?
On a modern operating system, it won’t cause any harm – all resources are reclaimed automatically when a program terminates. However, it does make it harder to use tools like Valgrind to find genuine problems, so it’s best to avoid even harmless memory leaks if you can.
Peter Wood
#include<iostream>
using namespace std;
int main()
{
{
std::string myname("Is there any leaks");
}
exit(0);
}
John Humphreys
At the time your process is actually exiting, as when main() exits, the OS will reclaim all resources allocated to your application either way. How you exit isn’t so important – at least with regard to dynamic memory.
If you have some distributed database connection open or something, you should use atexit() handlers to close it, and forceful termination with straight-up exit may make them not run which would be bad – but as far as your OS resources are concerned you’re probably okay.
You should also always make sure you release (manual) file locks and similar things as they may not go away due to a process exit.
Wenn Sie einen Wert von main() zurückgeben, wird dieser Wert als Exit-Code Ihres Prozesses verwendet.
– Blechmann
27. Januar 2012 um 13:43 Uhr
Beachten Sie, dass Sie, wie valgrind richtig betont, in diesem Fall keine durchgesickerten Ressourcen haben. Es gibt nur ein paar Bytes zugewiesenen Speichers, die am Ende der Prozesslebensdauer noch erreichbar sind (auf die Sie noch einen Zeiger haben), aber das ist kein “Leck”.
– Frerich Raabe
27. Januar 2012 um 14:30 Uhr
Wie Sie sicherlich schon gelesen haben, “return exitcode;” ist viel besser als “exit(exitcode);” weil beide den Exit-Code-Status setzen. “return” erledigt die Bereinigung viel besser, während “exit” wahrscheinlich die Bereinigung umgeht.
– Stephen Quan
27. Januar 2012 um 14:37 Uhr
Haben Sie andere Tools außer Valgrind ausprobiert? Zum Beispiel Deleaker…
– MastAvalons
27. Januar 2012 um 20:52 Uhr
Beachten Sie, dass, wenn Sie einen Wert von zurückgeben
main()
es ist nicht wirklich einint
. Es wird in den gültigen Bereich von Exit-Codes konvertiert, d. h[0,256)
(at least for Posix).Feb 2, 2012 at 19:15