std::string 中的内存泄漏
Memory leak in a std::string
如果用户在 shell 命令行中输入 "shutdown" 或 "restart",我试图让我的 shell 终止。一切正常。我使用 C (strtok
, cstring
) 和 C++ 来编写代码。当我使用 valgrind 时,它说仍然可以到达 1 个块。我知道这不是泄漏,但我很想知道是什么原因造成的以及如何解决。花了 2 天时间试图找到它,但找不到。请查看我的代码和 valgrind 报告。
代码
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
using namespace std;
const int MAX_COMMAND_LINE_ARGUMENTS = 8;
const int SLEEP_DELAY = 100000;
int GetCommand (string tokens []);
int TokenizeCommandLine (string tokens [], string commandLine);
bool CheckForCommand ();
void ProcessCommand (string tokens [], int tokenCount);
void ShutdownAndRestart (string tokens [], int tokenCount);
static volatile sig_atomic_t cullProcess = 0;
int main()
{
string tokens [MAX_COMMAND_LINE_ARGUMENTS];
int tokenCount;
do
{
tokenCount = GetCommand (tokens);
ProcessCommand (tokens, tokenCount);
} while (1);
return 0;
}
int GetCommand (string tokens [])
{
string commandLine;
bool commandEntered;
int tokenCount;
do
{
cout << "shell> ";
while (1)
{
getline (cin, commandLine);
commandEntered = CheckForCommand (); if (commandEntered)
{
break;
}
}
} while (commandLine.length () == 0);
tokenCount = TokenizeCommandLine (tokens, commandLine);
commandLine.clear();
return tokenCount;
}
int TokenizeCommandLine (string tokens [], string commandLine)
{
char *token [MAX_COMMAND_LINE_ARGUMENTS];
char *workCommandLine = new char [commandLine.length () + 1];
int i;
int tokenCount;
for (i = 0; i < MAX_COMMAND_LINE_ARGUMENTS; i ++)
{
tokens [i] = "";
}
strcpy (workCommandLine, commandLine.c_str ());
i = 0;
if ((token [i] = strtok (workCommandLine, " ")) != NULL)
{
i ++;
while ((token [i] = strtok (NULL, " ")) != NULL)
{
i ++;
}
}
tokenCount = i;
for (i = 0; i < tokenCount; i ++)
{
tokens [i] = (string) token [i];
}
delete [] workCommandLine;
return 0;
}
bool CheckForCommand ()
{
if (cullProcess)
{
cullProcess = 0;
cin.clear ();
cout << "\b\b \b\b";
return false;
}
return true;
}
void ProcessCommand (string tokens [], int tokenCount)
{
if (tokens [0] == "shutdown" || tokens [0] == "restart")
{
ShutdownAndRestart (tokens, tokenCount);
return;
}
}
void ShutdownAndRestart (string tokens [], int tokenCount)
{
if (tokenCount > 1)
{
cout << "shell: " << tokens [0] << " does not require any arguments" << endl;
return;
}
cout << endl;
cout << "shell: terminating ..." << endl;
exit(0);
}
VALGRIND
valgrind --leak-check=full --show-leak-kinds=all --show-reachable=yes tryThis
==20257== Memcheck, a memory error detector
==20257== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==20257== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==20257== Command: tryThis
==20257==
shell> shutdown
shell: terminating ...
==20257==
==20257== HEAP SUMMARY:
==20257== in use at exit: 33 bytes in 1 blocks
==20257== total heap usage: 6 allocs, 5 frees, 157 bytes allocated
==20257==
==20257== 33 bytes in 1 blocks are still reachable in loss record 1 of 1
==20257== at 0x4C2A203: operator new(unsigned long) (vg_replace_malloc.c:334)
==20257== by 0x4EF3CF8: allocate (new_allocator.h:104)
==20257== by 0x4EF3CF8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (basic_string.tcc:607)
==20257== by 0x4EF5580: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (basic_string.tcc:138)
==20257== by 0x4EF59B7: _S_construct_aux<char const*> (basic_string.h:1725)
==20257== by 0x4EF59B7: _S_construct<char const*> (basic_string.h:1746)
==20257== by 0x4EF59B7: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (basic_string.tcc:215)
==20257== by 0x40134D: TokenizeCommandLine(std::string*, std::string) (in xxx/tryThis)
==20257== by 0x4011C7: GetCommand(std::string*) (in xxx/tryThis)
==20257== by 0x4010CA: main (in xxx/tryThis)
==20257==
==20257== LEAK SUMMARY:
==20257== definitely lost: 0 bytes in 0 blocks
==20257== indirectly lost: 0 bytes in 0 blocks
==20257== possibly lost: 0 bytes in 0 blocks
==20257== still reachable: 33 bytes in 1 blocks
==20257== of which reachable via heuristic:
==20257== stdstring : 33 bytes in 1 blocks
==20257== suppressed: 0 bytes in 0 blocks
==20257==
==20257== For counts of detected and suppressed errors, rerun with: -v
==20257== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
您通过调用 exit(0)
.
的 ShutdownAndRestart()
退出程序
exit()
不会展开堆栈,它 "aborts" 程序只需要最少的清理。具体来说,main()
中的 tokens
变量不会被破坏,包含的字符串的内存也不会被释放。
如果您通过 returning 从 main 退出程序,问题应该会消失。例如 ProcessCommand()
可以 return 一个指示主循环是否应该停止的标志,而不是在内部调用 exit()
。
如果用户在 shell 命令行中输入 "shutdown" 或 "restart",我试图让我的 shell 终止。一切正常。我使用 C (strtok
, cstring
) 和 C++ 来编写代码。当我使用 valgrind 时,它说仍然可以到达 1 个块。我知道这不是泄漏,但我很想知道是什么原因造成的以及如何解决。花了 2 天时间试图找到它,但找不到。请查看我的代码和 valgrind 报告。
代码
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
using namespace std;
const int MAX_COMMAND_LINE_ARGUMENTS = 8;
const int SLEEP_DELAY = 100000;
int GetCommand (string tokens []);
int TokenizeCommandLine (string tokens [], string commandLine);
bool CheckForCommand ();
void ProcessCommand (string tokens [], int tokenCount);
void ShutdownAndRestart (string tokens [], int tokenCount);
static volatile sig_atomic_t cullProcess = 0;
int main()
{
string tokens [MAX_COMMAND_LINE_ARGUMENTS];
int tokenCount;
do
{
tokenCount = GetCommand (tokens);
ProcessCommand (tokens, tokenCount);
} while (1);
return 0;
}
int GetCommand (string tokens [])
{
string commandLine;
bool commandEntered;
int tokenCount;
do
{
cout << "shell> ";
while (1)
{
getline (cin, commandLine);
commandEntered = CheckForCommand (); if (commandEntered)
{
break;
}
}
} while (commandLine.length () == 0);
tokenCount = TokenizeCommandLine (tokens, commandLine);
commandLine.clear();
return tokenCount;
}
int TokenizeCommandLine (string tokens [], string commandLine)
{
char *token [MAX_COMMAND_LINE_ARGUMENTS];
char *workCommandLine = new char [commandLine.length () + 1];
int i;
int tokenCount;
for (i = 0; i < MAX_COMMAND_LINE_ARGUMENTS; i ++)
{
tokens [i] = "";
}
strcpy (workCommandLine, commandLine.c_str ());
i = 0;
if ((token [i] = strtok (workCommandLine, " ")) != NULL)
{
i ++;
while ((token [i] = strtok (NULL, " ")) != NULL)
{
i ++;
}
}
tokenCount = i;
for (i = 0; i < tokenCount; i ++)
{
tokens [i] = (string) token [i];
}
delete [] workCommandLine;
return 0;
}
bool CheckForCommand ()
{
if (cullProcess)
{
cullProcess = 0;
cin.clear ();
cout << "\b\b \b\b";
return false;
}
return true;
}
void ProcessCommand (string tokens [], int tokenCount)
{
if (tokens [0] == "shutdown" || tokens [0] == "restart")
{
ShutdownAndRestart (tokens, tokenCount);
return;
}
}
void ShutdownAndRestart (string tokens [], int tokenCount)
{
if (tokenCount > 1)
{
cout << "shell: " << tokens [0] << " does not require any arguments" << endl;
return;
}
cout << endl;
cout << "shell: terminating ..." << endl;
exit(0);
}
VALGRIND
valgrind --leak-check=full --show-leak-kinds=all --show-reachable=yes tryThis
==20257== Memcheck, a memory error detector
==20257== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==20257== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==20257== Command: tryThis
==20257==
shell> shutdown
shell: terminating ...
==20257==
==20257== HEAP SUMMARY:
==20257== in use at exit: 33 bytes in 1 blocks
==20257== total heap usage: 6 allocs, 5 frees, 157 bytes allocated
==20257==
==20257== 33 bytes in 1 blocks are still reachable in loss record 1 of 1
==20257== at 0x4C2A203: operator new(unsigned long) (vg_replace_malloc.c:334)
==20257== by 0x4EF3CF8: allocate (new_allocator.h:104)
==20257== by 0x4EF3CF8: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (basic_string.tcc:607)
==20257== by 0x4EF5580: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (basic_string.tcc:138)
==20257== by 0x4EF59B7: _S_construct_aux<char const*> (basic_string.h:1725)
==20257== by 0x4EF59B7: _S_construct<char const*> (basic_string.h:1746)
==20257== by 0x4EF59B7: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (basic_string.tcc:215)
==20257== by 0x40134D: TokenizeCommandLine(std::string*, std::string) (in xxx/tryThis)
==20257== by 0x4011C7: GetCommand(std::string*) (in xxx/tryThis)
==20257== by 0x4010CA: main (in xxx/tryThis)
==20257==
==20257== LEAK SUMMARY:
==20257== definitely lost: 0 bytes in 0 blocks
==20257== indirectly lost: 0 bytes in 0 blocks
==20257== possibly lost: 0 bytes in 0 blocks
==20257== still reachable: 33 bytes in 1 blocks
==20257== of which reachable via heuristic:
==20257== stdstring : 33 bytes in 1 blocks
==20257== suppressed: 0 bytes in 0 blocks
==20257==
==20257== For counts of detected and suppressed errors, rerun with: -v
==20257== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
您通过调用 exit(0)
.
ShutdownAndRestart()
退出程序
exit()
不会展开堆栈,它 "aborts" 程序只需要最少的清理。具体来说,main()
中的 tokens
变量不会被破坏,包含的字符串的内存也不会被释放。
如果您通过 returning 从 main 退出程序,问题应该会消失。例如 ProcessCommand()
可以 return 一个指示主循环是否应该停止的标志,而不是在内部调用 exit()
。