0

この問題を解決するにはメモリ管理が悪い?クラス メンバー (ブール値) の値が 1 より大きい、再帰関数で、Valgrind でプログラム全体を実行したところ、ステップの前に発生したメモリ リークの問題がいくつか見つかりました。関数 CMFLoader で識別された 2 つの「確実に失われた」問題がありました。

(ここで MyDataset は Molecule オブジェクトのベクトルであり、各 Molecule オブジェクトには Elements オブジェクトが含まれています)

CMFLoader::loadFile(vector& MyDataset) では、もともと

MyDataset.push_back( readMolecule( in_file, word );

ここで、CMFLoader::readMolecule は Molecule オブジェクトを返します。readMolecule 関数内で、新しい Molecule オブジェクトが作成されます (ただし、main の最後まで削除されません。詳細は後で説明します)。

Molecule* CMFLoader::readMolecule( ifstream& in_file, string id)
{
Molecule* my_mol = new Molecule( id );
// statements, somewhere along the readFormula function is called
my_mol->setFormula( readFormula( ss ) );
return my_mol;
}

ここで、CMFLoader::readFormula は Element オブジェクトを返し、それを Molecule オブジェクトに保存する Molecule::setFormula 関数があります。読み取り式で

Elements* CMFLoader::readFormula( stringstream& ss )
{
Elements* my_formula = new Elements();
...
return my_formula;
}

ここの質問で説明されている問題に遭遇しました。メインプログラムの後半で。特定の問題は HammettCheck::checkHammett ステップで発生しました。次に、上記の CMFLoader 関数を次のように変更しました。以前に遭遇した問題は解消されたようです (ただし、メモリ リークに関連していると思われる他の問題がプログラムの後半にありました)。

CMFLoader::loadFile で

Molecule* new_mol = new Molecule(word);
    MyDataset.push_back( readMolecule( in_file, word ,new_mol) );

ここで、readMolecule は新しい引数 Molecule* を取り、新しい演算子は関数内で削除されます。同様に、readFormula では、次のようになりました。

 Elements* new_formula = new Elements();
my_mol->setFormula( readFormula( ss, new_formula ) );

もちろん、メモリ リークの問題は解消されていません。ただし、オブジェクトは後でメイン プログラムで使用されるため、CMFLoader 関数内に削除演算子を配置することはできません。具体的には、Elements* は ConjugationCheck::checkConjugation ステップまで使用され、Molecule* はプログラムが終了するまで使用されます。

主なプログラムは次のようになります

int main(int argc, char* argv[]){
//initialising an empty array to store our molecules.
vector<Molecule*> MyDataset;

//Read command line inputs.
InputReader* MyInputs = new InputReader();
if( !MyInputs->readInputs(argc, argv) ) {delete MyInputs;return -1;}

//Load CMF file.
CMFLoader* MyLoader = new CMFLoader( MyInputs );
unsigned int min_same_grp = MyLoader->getmin(); //define minimum no of same hammett groups for structure
if( !MyLoader->loadFile( MyDataset ) ) {delete MyLoader;delete MyInputs;return -1;}
delete MyLoader;

cout << MyDataset.size() << " molecules loaded" << endl;

//Remove molecules which are too large.
BigFilter* MyBigFilter = new BigFilter( MyInputs );
if( !MyBigFilter->filterBigLigands( MyDataset ) ) {delete MyBigFilter;delete MyInputs;return -1;}
delete MyBigFilter;

cout << "Molecules left after big ligand filter: " << MyDataset.size() << endl;

//Mark any Hammetts groups found in molecules.
HammettCheck* MyHammettCheck = new HammettCheck(min_same_grp);
if( !MyHammettCheck->loadHammetts() ) {delete MyHammettCheck;delete MyInputs;return -1;}
if( !MyHammettCheck->checkHammett( MyDataset ) ) {delete MyHammettCheck;delete MyInputs;return -1;}
delete MyHammettCheck;

cout << "Molecules containing Hammett Groups: " << MyDataset.size() << endl;

ConjugationCheck* MyConjugationCheck = new ConjugationCheck(min_same_grp);
if( !MyConjugationCheck->checkConjugation( MyDataset ) ) {delete MyConjugationCheck;delete MyInputs;return -1;}
delete MyConjugationCheck;

cout << "Molecules containing conjugated Hammett Groups: " << MyDataset.size() << endl;

DataAdder* MyDataAdder = new DataAdder( MyInputs );
if( !MyDataAdder->addData( MyDataset ) ) {delete MyDataAdder; delete MyInputs;return -1;}
delete MyDataAdder;

//Sorts molecules based on their NLO rating given by NLOCompare.
if (min_same_grp ==1) {sort(MyDataset.begin(), MyDataset.end(), NLOCompare);}
else {sort(MyDataset.begin(), MyDataset.end(), OctuNLOCompare);}

//Saves a new CIF file containing just the predicted NLO molecules.
FileSaver* MyFileSaver = new FileSaver( MyInputs );
if( !MyFileSaver->saveFile( MyDataset ) ) {delete MyFileSaver;delete MyInputs;return -1;}
delete MyFileSaver;

/*
Saves a txt file which can be imported into Excel, showing the
paths to each of the selected Hammett groups in a molecule.
*/
ExcelSaver* MyExcelSaver = new ExcelSaver( MyInputs );
if( !MyExcelSaver->saveFile( MyDataset ) ) {delete MyExcelSaver;delete MyInputs;return -1;}
delete MyExcelSaver;

//Cleans the memory before exiting the program.
for(unsigned int i=0; i < MyDataset.size(); i++){
    delete MyDataset[i];
}
delete MyInputs;
return 0;
}

プログラムのさまざまな時点で、Molecule MyDataset[i] が特定の条件に適合しない場合、次を使用して削除されます

MyDataset.pop_back();

したがって、これは Molecule Destructor を呼び出します。これは次のようになります。

Molecule::~Molecule(void)
{
//Deletes all atoms in molecule.
for(unsigned int i=0; i < mol_atoms.size(); i++){
    delete mol_atoms[i];
}

//Deletes all bonds in molecule.
for(unsigned int i=0; i < mol_bonds.size(); i++){
    delete mol_bonds[i];
}

//Deletes the class of elements contained.
delete mol_formula;
}

ここで何がうまくいかなかったのかわかりません。メモリリークの問題を修正するにはどうすればよいですか?

私のValgrind Memcheckリークの要約における「間違いなく損失」の問題

==34809== 400 (96 direct, 304 indirect) bytes in 2 blocks are definitely lost in loss record 24 of 33
==34809==    at 0x1000A0679: malloc (vg_replace_malloc.c:266)
==34809==    by 0x1000F7F04: operator new(unsigned long) (in /usr/lib/libstdc++.6.0.9.dylib)
==34809==    by 0x10000A3B4: CMFLoader::readMolecule(std::basic_ifstream<char, std::char_traits<char> >&, std::string, Molecule*) (in ./OctuDiscovery)
==34809==    by 0x10000B9EE: CMFLoader::loadFile(std::vector<Molecule*, std::allocator<Molecule*> >&) (in ./OctuDiscovery)
==34809==    by 0x10000282E: main (in ./OctuDiscovery)

==34809== 12,833 (152 direct, 12,681 indirect) bytes in 1 blocks are definitely lost in loss record 33 of 33
==34809==    at 0x1000A0679: malloc (vg_replace_malloc.c:266)
==34809==    by 0x1000F7F04: operator new(unsigned long) (in /usr/lib/libstdc++.6.0.9.dylib)
==34809==    by 0x10000B93B: CMFLoader::loadFile(std::vector<Molecule*, std::allocator<Molecule*> >&) (in ./OctuDiscovery)
==34809==    by 0x10000282E: main (in ./OctuDiscovery)
4

2 に答える 2

2

答えよりもコメントですが、コメントには長すぎます:
次の関数では、動的メモリを使用する意味がありません:

Molecule* CMFLoader::readMolecule( ifstream& in_file, string id)
{
Molecule* my_mol = new Molecule( id );
// statements, somewhere along the readFormula function is called
my_mol->setFormula( readFormula( ss ) );
return my_mol;
}

次のように置き換えることができます。

Molecule CMFLoader::readMolecule( ifstream& in_file, string id)
{
Molecule my_mol( id );
// statements, somewhere along the readFormula function is called
my_mol.setFormula( readFormula( ss ) );
return my_mol;
}

これにより、メモリ リークの可能性がすでに 1 つ解決されていますが、動的メモリ バージョンが必要または優先される理由がある可能性があります。その場合は、前述の unique_ptr を使用する必要があります。

于 2012-05-11T11:33:41.673 に答える
1

このようなことをしたい場合は、std :: auto_ptrクラス、または少なくともスマートポインター、または自動ポインターの概念を確認することをお勧めします。RAII(Resource Aquisition Is Initialization)パラダイムに依存する必要があります。つまり、メモリ管理はオブジェクト自体で実行する必要があります。可能な限り、基本的なポインターや自己記述のメモリ管理コードは避けてください。

于 2012-05-11T11:25:26.693 に答える