Problem mit Speicherverbrauch beim benutzung von MySQL

FBIagent

Erfahrenes Mitglied
Moin,

ich habe da ein Problem beim Speicherverbrauch beim benutzen von MySQL.

Ich starte das Programm und gucke in den Task-Manager.
Es startet mit ca. 1.500 K
Ich lasse es länger laufen und der Speicherverbrauch steigt rapide.

Hier erstmal der Code:
dna.cpp (dna steht für "delete not active")
Code:
#include <iostream>
#include <fstream>
#include <vector>
#include <time.h>
#include <windows.h>
#include <MySQL/mysql.h>
#include "mysqlcon.h"
 
mConnection mCon;
 
void checkAccounts()
{
  bool all_fine;
  std::string accLogin;
  int accRegTime;
  
  std::cout << "Starting loop to check accounts register time in 5 seconds...\n\n\n";
  Sleep(5000);

  for(;;)
  {
    all_fine = true;
 
    std::cout << "Next accounts register time check now!\n";
    std::cout << "Get accounts from database... ";
    mCon.query("SELECT * FROM `accounts_unchecked`");
    MYSQL_RES *acc_res = mCon.lastRes();
    std::cout << "done.\n";

    std::cout << "Check accounts... ";
    while(MYSQL_ROW acc_row = mysql_fetch_row(acc_res))
    {
      accLogin = acc_row[0];
      accRegTime = atoi(acc_row[7]);

      if((accRegTime+2592000)<time(NULL))
      {
        all_fine = false;
        std::cout << "\nDelete account:" << accLogin;
        mCon.query("DELETE FROM `accounts_unchecked` WHERE `login`='"+accLogin+"';");
      }

    }
 
    if(all_fine == true)
      std::cout << "all fine.\n\n";
    else
      std::cout << "\n\ndone.\n\n";
 
    std::cout << "Next accounts check in 5 minutes.\n\n\n";
//    mCon.queryFree();
    Sleep(300000);
  }
}
 
int main()
{
  bool running = true;
 
  std::cout << "Loading config... ";
  if(mCon.loadConfig() == true)
    std::cout << "successfull.\n";
  else
  {
    std::cout << "failed.\n Error: Can't find config.txt\n\n";
    running = false;
  }
 
  if(running == true)
  {
    std::cout << "Connecting to MySQL server... ";

    if(mCon.connect() == true)
    {
      std::cout << "successfull.\n\n";
      checkAccounts();
    }
    else
      std::cout << "failed.\nError: Can't connect to MySQL server. Wrong configs or server down?\n\n";

  }
 
  mCon.close();
  system("Pause");
  return 0;
}

mysqlcon.h
Code:
#ifndef MY_MYSQLCON_H
#define MY_MYSQLCON_H
 
class mConnection
{
private:
  MYSQL mCon;
  MYSQL_RES *mRes;
  std::string mInfo[4];
public:
  bool loadConfig();
  bool connect();
  bool query(std::string data);
  MYSQL_RES *lastRes();
  void queryFree();
  void close();
};
 
bool mConnection::loadConfig()
{
  std::string row;
  std::vector<std::string> rows;
  std::ifstream file("config.txt");
  
  if(!file.is_open())
    return false;
  
  while(getline(file,row))
    rows.push_back(row);
  for(int i=0;i<rows.size();i++)
    mInfo[i] = rows[i];
 
  return true;
}
 
bool mConnection::connect()
{
  mysql_init(&mCon);
  if(mysql_real_connect(&mCon,mInfo[0].c_str(),mInfo[1].c_str(),mInfo[2].c_str(),mInfo[3].c_str(),3306,NULL,0))
    return true;
  else
    return false;
}
 
bool mConnection::query(std::string data)
{
  if(!mysql_query(&mCon,data.c_str()))
    return false;
  else
    return true;
}
 
MYSQL_RES *mConnection::lastRes()
{
  return mysql_store_result(&mCon);
}
 
void mConnection::queryFree()
{
  mysql_free_result(mRes);
}
 
void mConnection::close()
{
  mysql_close(&mCon);
}
 
#endif

Wie kann ich den jetzt den rapiden Speicherverbrauchsanstieg stoppen?
(Rapider Speicherverbrauch in der Funktion checkAccounts(); )

THX im Vorraus
MFG FBIagent
 
Zuletzt bearbeitet:
Hi.

Aus der MySQL Doku (http://dev.mysql.com/doc/refman/5.0/en/mysql-store-result.html):
You must call mysql_free_result() once you are done with the result set.

Du solltest übrigens prüfen ob der Pointer 0 ist den mysql_store_result() zurückgibt.

Gruß

/edit: Übrigens, warum schreibst du eigentlich deinen eigenen C++ Wrapper statt einen (der zahlreichen) vorhandenen zu benutzen? (http://www.alhem.net/project/mysql/ oder http://mysqlcppapi.sourceforge.net/)
 
Zuletzt bearbeitet:
Wie du vieleicht siehst benutze ich die Methode queryFree(); aus mConnection in der
mysqs_free_result(mRes);
Ich habe es mit diesem Aufruf und ohne ihn laufen lassen. Der
Speicherverbrauchsanstieg steig trotzdem stätiganstieg.

Hm... ich lasse mir das letzte Resultat ja mit lastRes(); geben liegt es vieleicht daran
das ich acc_res nicht freigebe? Wenn ja wie kann ich den eine Variable aus einer Klasse mit einer
globalen Variable referenzieren?

Ich versuche mal was über parameter zu referenzieren mal sehen.

THX im Vorraus
MFG FBIagent

EDIT: War ganz einfach hier der Code den Speicher nicht in die höhe treibt :)

dna.cpp
Code:
#include <iostream>
#include <fstream>
#include <vector>
#include <time.h>
#include <windows.h>
#include <MySQL/mysql.h>
#include "mysqlcon.h"

mConnection mCon;

void checkAccounts()
{
  bool all_fine;
  std::string accLogin;
  int accRegTime;
  
  std::cout << "Starting loop to check accounts register time in 5 seconds...\n\n\n";
  Sleep(5000);

  for(;;)
  {
    all_fine = true;

    std::cout << "Next accounts register time check now!\n";
    std::cout << "Get accounts from database... ";
    mCon.query("SELECT * FROM `accounts_unchecked`");
    MYSQL_RES *acc_res = mCon.lastRes();
    std::cout << "done.\n";

    std::cout << "Check accounts... ";

    while(MYSQL_ROW acc_row = mysql_fetch_row(acc_res))
    {
      accLogin = acc_row[0];
      accRegTime = atoi(acc_row[7]);
      if((accRegTime+2592000)<time(NULL))
      {
        all_fine = false;
        std::cout << "\nDelete account:" << accLogin;
        mCon.query("DELETE FROM `accounts_unchecked` WHERE `login`='"+accLogin+"';");
      }
    }

    if(all_fine == true)
      std::cout << "all fine.\n\n";
    else
      std::cout << "\n\ndone.\n\n";

    std::cout << "Next accounts check in 5 minutes.\n\n\n";
    mCon.resFree(acc_res);
    Sleep(300000);
  }
}

int main()
{
  bool running = true;

  std::cout << "Loading config... ";

  if(mCon.loadConfig() == true)
    std::cout << "successfull.\n";
  else
  {
    std::cout << "failed.\n Error: Can't find config.txt\n\n";
    running = false;
  }

  if(running == true)
  {
    std::cout << "Connecting to MySQL server... ";
    if(mCon.connect() == true)
    {
      std::cout << "successfull.\n\n";
      checkAccounts();
    }
    else
      std::cout << "failed.\nError: Can't connect to MySQL server. Wrong configs or server down?\n\n";
  }

  mCon.close();
  system("Pause");
  return 0;
}

mysqlcon.h
Code:
#ifndef MY_MYSQLCON_H
#define MY_MYSQLCON_H

class mConnection
{
private:
  MYSQL mCon;
  MYSQL_RES *mRes;
  std::string mInfo[4];
public:
  bool loadConfig();
  bool connect();
  bool query(std::string data);
  MYSQL_RES *lastRes();
  void resFree(MYSQL_RES *data);
  void close();
};

bool mConnection::loadConfig()
{
  std::string row;
  std::vector<std::string> rows;
  std::ifstream file("config.txt");
  
  if(!file.is_open())
    return false;
  
  while(getline(file,row))
    rows.push_back(row);

  for(int i=0;i<rows.size();i++)
    mInfo[i] = rows[i];

  return true;
}

bool mConnection::connect()
{
  mysql_init(&mCon);
  if(mysql_real_connect(&mCon,mInfo[0].c_str(),mInfo[1].c_str(),mInfo[2].c_str(),mInfo[3].c_str(),3306,NULL,0))
    return true;
  else
    return false;
}

bool mConnection::query(std::string data)
{
  if(!mysql_query(&mCon,data.c_str()))
    return false;
  else
    return true;
}

MYSQL_RES *mConnection::lastRes()
{
  return mysql_store_result(&mCon);
}

void mConnection::resFree(MYSQL_RES *data)
{
  mysql_free_result(data);
}

void mConnection::close()
{
  mysql_close(&mCon);
}

#endif
 
Zuletzt bearbeitet:
Vielleicht solltest du einfach die lastRes Funktion ungefähr so definieren:
Code:
MYSQL_RES *mConnection::lastRes()
{
  return mRes = mysql_store_result(&mCon);
}
Dann wird auch wirklich was freigegeben wenn freeQuery() aufgerufen wird (ungünstiger Name übrigens, denn die Query wird ja nicht freigegeben sondern das Resultat).

Obwohl ich dir empfehlen würde das Resultat innerhalb einer Klasse zu kapseln so das von außen nicht mehr direkt auf den Pointer zugegriffen werden kann und das evtl. automatisch im Destruktor ein mysql_free_result() aufgerufen wird.

Gruß

/edit: Wer hat denn das "Daumen-hoch"-Icon neben die Themenüberschrift gemacht? War ich das etwa? :-)
 
Zuletzt bearbeitet:
Hm... kapseln... das müsstest du mir nochmal eher erklären.
Aber wenn ich konstruktor und destruktor benutzen will muss ich dann nicht mit new
und delete arbeiten?

Mit
Code:
return mysql_store_result(&mCon);
funktioniert alles bestens.

Eins verstehe ich nicht warum funtzt es wenn ich acc_res an die Funktion freeRes(); übergebe. Ich sehe auch
gerade das aus der Klasse der Pointer (mRes) aus für MYSQL_RES auch garnicht benutzt wird, und somit total
unnütz ist... Dummer Fehler meinerseits.

Eine frage bleibt für mich aber noch offen... Ich übergebe ja acc_res an freeRes();
Code:
mCon.freeRes(acc_res);
Aber ich Referenziere den Parameter data ja meineserachtens nicht.

Warum wird acc_res dann freigeräumt?

THX im Vorraus
MFG FBIagent
 
Zuletzt bearbeitet:
FBIagent hat gesagt.:
Hm... kapseln... das müsstest du mir nochmal eher erklären.
Kapselung ist ein wichtiger Bestandteil der objektorientierten Programmierung. Allerdings glaube ich das das etwas zu früh ist dir da was drüber zu erzählen. Du scheinst momentan noch mehr Probleme damit zu haben einfachen Code von der Bedeutung her erfassen zu können.
FBIagent hat gesagt.:
Aber wenn ich konstruktor und destruktor benutzen will muss ich dann nicht mit new
und delete arbeiten?
Nein. Konstruktoren und Desktruktoren werden immer aufgerufen wenn eine Instanz einer Klasse erstellt bzw. vernichtet wird - ganz gleich wo es erstellt und wie es verwaltet wird.

FBIagent hat gesagt.:
Mit
Code:
return mysql_store_result(&mCon);
funktioniert alles bestens.
Du hast anscheinend nicht verstanden was der Code bedeutet den ich vorgeschlagen habe.

FBIagent hat gesagt.:
Eins verstehe ich nicht warum funtzt es wenn ich acc_res an die Funktion freeRes(); übergebe. Ich sehe auch
gerade das aus der Klasse der Pointer (mRes) aus für MYSQL_RES auch garnicht benutzt wird, und somit total
unnütz ist... Dummer Fehler meinerseits.
Dazu war ja auch die Änderung gedacht die ich (der Einfachheit halber) vorgeschlagen hatte. Dann wäre nämlich mRes immer auf das aktuelle Resultat gesetzt gewesen und die queryFree() Funktion hätte funktionert.

FBIagent hat gesagt.:
Eine frage bleibt für mich aber noch offen... Ich übergebe ja acc_res an freeRes();
Code:
mCon.freeRes(acc_res);
Aber ich Referenziere den Parameter data ja meineserachtens nicht.

Warum wird acc_res dann freigeräumt?
Was hat denn das mit dem String data zu tun? MySQL speichert das Resultat der Anfrage und man erhält auf Anforderung einen Pointer auf ein MYSQL_RES für das natürlich Speicher alloziert wurde. Dieser Speicher muß dann auch wieder freigegeben werden.

Gruß
 
Zurück