Speicherleck C++

Lesezeit: 8 Minuten

Benutzeravatar von Global Warrior
Globaler Krieger

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's user avatar
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.

http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx

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's user avatar
Peter Wood

#include<iostream>
using namespace std;
int main()
{
    {
        std::string myname("Is there any leaks");
    }
    exit(0);
}

John Humphreys's user avatar
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.

1406330cookie-checkSpeicherleck C++

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy