Speicherverwaltung schreiben: Problem bei assert und free.



  • Hi,

    ich habe die Aufgabe eine Speicherverwaltung zu programmieren. Dazu gab es vom Professor eine Vorlage.

    Hab 3 Tage dran gearbeitet. Hier sind die Unterlagen:
    http://www.share-online.biz/dl/0LI8133P5S1

    Bei der Ausführung führt Zeile 8 "assert(m_size == 0xcdcd);" in MemoryTesterElement zu einer Ausnahme.
    Bisher habe ich noch nicht verstanden warum. Dies war vorgegebener Code vom Professor und da das Objekt hier erst erstellt wird dürfte der Inhalt von m_size ja random sein.

    Kommentiere ich diese beiden Asserts aus, dann kommt es zu einer Ausnahme bei den free-Befehlen im Destruktor von Bucket.cpp. Hier weiß ich auch nicht warum.

    Inhalt des zip:

    • Ordner "Aufgabe6Material" beinhaltet den von mir bearbeiteten Code.
    • "Aufgabe6Material.zip" beinhaltet den orignalen vorgegebenen Code. Im Grunde waren BucketAdmin.cpp und Bucket.cpp so gut wie leer. BucketSystem.cpp und MemoryTesterElement.cpp waren fertig ausgefüllt und wurden nicht geändert.
    • "Vorlesung6_SP.pdf" ist die zugehörige Vorlesung. Seiten 19 bis 25 sind einschlägig sehr relevant. Die Vorlesung gibts auch mit Audiokommentar unter http://public.hochschule-trier.de/~luerig/SP/6/
    • "Zettel6.pdf" beinhaltet die Aufgabenstellung.

    Danke - Enomine



  • Dann wirst du wohl noch ein paar Tage mehr investieren müssen.



  • Ist das Dein Ernst, bei einem Raubkopien-Hoster hochzuladen, wo man ohne Zahlung erst mal ne gute Minute warten darf und dann mit tollen 100 kB/s runterladen kann?



  • Kannst du den Code nicht einfach posten? Diese Runterladerei ist lästig.



  • Seine MemoryTesterElement schaut so aus:

    #pragma once
    
    // Class simply allocates memory and fills the array with defined values
    // that we can check if memory corruption occured.
    class MemoryTesterElement
    {
    public:
    	// The allocated memory is four times the amount of size.
    	MemoryTesterElement(unsigned short size);
    	~MemoryTesterElement(void);
    
    private:
    	// A first element 
    	unsigned short m_size;
    	// The test memory used.
    	unsigned int* m_testMemory;
    	// The size we store.
    	unsigned short m_sizeCopy;
    };
    
    #include "StdAfx.h"
    #include "MemoryTesterElement.h"
    #include <assert.h>
    
    MemoryTesterElement::MemoryTesterElement(unsigned short size)
    {
    	assert(m_size == 0xcdcd);
    	assert(m_sizeCopy == 0xcdcd);
    	m_size = m_sizeCopy = size;
     	m_testMemory = new unsigned int [m_size];
    	// We fill the test memory with our pointer.
    	unsigned int ourSelves = (unsigned int)this;
    	for(int i = 0; i < m_size; ++i)
    	{
    		assert(m_testMemory[i] == 0xcdcdcdcd);
    		m_testMemory[i] = ourSelves;
    	}
    }
    
    MemoryTesterElement::~MemoryTesterElement(void)
    {	
    	assert(m_size == m_sizeCopy);
    	unsigned int ourSelves = (unsigned int)this;
    	for(int i = 0; i < m_size; ++i)
    	{
    		assert(m_testMemory[i] == ourSelves);
    	}
    	delete [] m_testMemory;
    }
    


  • Printe schrieb:

    Kannst du den Code nicht einfach posten? Diese Runterladerei ist lästig.

    Gern. Hatte nur gedacht, es sei einfacher mit dem ganzen Projekt.

    Aufgabenbeschreibung:

    Übungszettel Systemprogrammierung
    Ziel dieser Aufgabe ist es ein Bucket Memory Manager mit festen Budgets zu erstellen, wie er in der Vorlesung vorgestellt worden ist. Eine Skeletimplementierung finden Sie in dem bereitgestellten Material. Diese Implementierung enthält ein Stresstestbed, an dem Sie Ihre fertige Implementierung des Memory Managers testen können. Die Hauptdatei ist "BucketSystem.cpp". Hier sind global die new und delete Operatoren überladen und das Testbed ist implementiert.

    Die new und delete Operatoren versuchen zunächst den Speicher aus dem Bucket System zu benutzen und verwenden ansonsten das normale "malloc" und "free", um auf den Hauptspeicher zuzugreifen. Um Fehler in dem System einfach erkennen zu können, soll initialer Speicher immer mit dem Muster "0xcd" vorinitialisiert sein. In dem Bucketsystem wird der Speicher am Anfang mit diesem Wert vorinitialisiert und bei jedem Löschen von Speicher wieder darauf zurückgesetzt. Damit die Speicheranforderungen, die über malloc laufen kompatibel sind, wird hier bei der Allokation des Speichers dieser vorinitialisiert.

    Die Klasse "MemoryTesterElement" enthält ein Testelement, dass am Anfang überprüft, ob der Speicher dem Löschmuster "oxcd" entspricht. Auf diese Art wird überprüft, ob das Element auch wirklich Speicher verwendet, der komplett neu ist oder freibegeben worden ist. Danach trägt es seine eigene Adresse in den Speicher ein. Im Destruktor des Elementes wird wieder eine Konsistenzprüfung vorgenommen, ob noch alle Werte dem angeforderten entsprechen.

    Die beiden Klassen "BucketAdmin" und "Bucket" sind noch nicht ausprogrammiert und sollen von Ihnen geschrieben werden. Ein Bucket ist dabei ein Stück Speicher, das Speicherportionen einer gewissen Granularität zur Verfügung stellt. Diese Buckets werden im BucketAdmin verwaltet. Geht eine Speicheranfrage in den BucketAdmin geht er alle Buckets von der kleinsten Granularität an durch und such ein Bucket, das seine Anforderung befriedigen kann. Bei dem Löschen versucht der BucketAdmin alle Buckets mit dem Speicher aufzurufen, bis sich ein Bucket dafür zuständig erklärt und den Speicher freigibt. Der in dem Headerfile definierte Wert BUCKET_CAPACITY gibt an, wie viele Speicherportionen wir in jedem Bucket verwalten.

    Die Klasse "Bucket" selber verwaltet ein Bucket mit allen Speicherhappen. Wir gehen hier davon aus, dass nie mehr als 65536 Speicherhappen verwaltet werden. Die Klasse Bucket verwaltet die einzelnen Happen, wie es in der Vorlesung bei dem Pooling System vorgestellt worden ist. In dem Array "m_freeChunks" wird effektiv ein Stack gespeichert, der die Indizes für die Memory Blöcke enthält, die herausgegeben werden können. Programmieren Sie den Bucket so, dass am Anfang alle Speicherblöcke mit "0xcd" vorinitialisiert werden. Benutzen Sie dazu die Methode "memset" aus dem Headerfile "memory.h". Jedes Mal, wenn ei n Stück Speicher erfolgreich wieder zurückgegeben wird, muss dieser Speicher auch wieder mit dem Füllmuster "0xcd" gefüllt werden.

    Wenn Sie die beiden Klassen "Bucket" und "BucketAdmin" implementieren, achten Sie darauf kein new und delete zu verwenden. Sonst haben Sie eine Katze, die sich in den Schwanz beißt. Verwenden Sie ausschließlich placement news, malloc und free.

    Wenn Ihr Programm fehlerfrei und ohne assertations durchläuft haben Sie Ihre erste Speicherverwaltung geschrieben. Wenn Sie jetzt in der Datei BucketSystem in den beiden new Routinen jeweils die erste Zeile auskommentieren und die zweite Zeile einkommentieren, verwenden Sie für alle Speicheranforderungen wieder das Standard malloc. Auf meinem Rechner ist die Variante mit dem eigenen Bucket Memory Manager gut doppelt so schnell. Dies ist noch ein Memory Manager der relativ dumm ist und wenig Kontextinformationen benutzt. Meine Praxiserfahrung hat gezeigt, dass sich durch eine schlaue Speicherverwaltung und -benutzung signifikante Performanzsteigerungen bewirken lassen. Diese Teile der Spieleprogrammierung sind zunächst einmal weniger interessant als Graphik, AI etc. trägt aber doch wesentlich zur Qualität des Endproduktes bei.

    BucketSystem.cpp:

    // BucketSystem.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    #include <new>
    #include <memory.h>
    #include <stdlib.h>
    #include "BucketAdmin.h"
    #include "MemoryTesterElement.h"
    
    BucketAdmin m_memoryManager;
    
    // The section with the new and delete operators.
    // They try to use the bucket system if possible and otherwise
    // default to the standard malloc and free.
    void* operator new(unsigned int size)
    {
    	void* result = m_memoryManager.RequestMemory(size);
    	// void* result = NULL;
    	if (!result)
    	{	
    		result = malloc(size);
    		// We fill the memory with the test pattern here to comply
    		// with the default that all memory is initialized with 0xcd.
    		memset(result, 0xcd, size);
    	}
    
    	return result;
    }
    
    void* operator new[](unsigned int size)
    {
    	void* result = m_memoryManager.RequestMemory(size);
    	// void* result = NULL;
    	if (!result)
    	{
    		result = malloc(size);
    		// We fill the memory with the test pattern here to comply
    		// with the default that all memory is initialized with 0xcd.
    		memset(result, 0xcd, size);
    	}
    	return result;
    }
    
    void operator delete(void* pointer)
    {
    	bool result = m_memoryManager.ReleaseMemory(pointer);
    	if (!result)
    		free(pointer);
    }
    
    void operator delete[](void * pointer)
    {
    	bool result = m_memoryManager.ReleaseMemory(pointer);
    	if (!result)
    		free(pointer);
    }
    
    // These are test routines to test the system.
    const int m_numOfTestElements = 4096;
    MemoryTesterElement* m_testArray[m_numOfTestElements];
    
    // We allocate some elements here.
    void FillInitialArray()
    {
    	for(int i = 0; i < m_numOfTestElements; ++i)
    		m_testArray[i] = new MemoryTesterElement(rand() % 64 + 1);
    }
    
    // We delete all remaining elements here.
    void CleanArray()
    {
    	for(int i = 0; i < m_numOfTestElements; ++i)
    	{
    		if (m_testArray[i])
    			delete m_testArray[i];
    	}
    }
    
    // Here we randomly delete and create  new elements.
    void PerformSingleTest()
    {
    	int element = rand() % m_numOfTestElements;
    	if (m_testArray[element])
    	{
    		delete m_testArray[element];
    		m_testArray[element] = NULL;
    	}
    	else
    	{
    		m_testArray[element] = new MemoryTesterElement(rand() % 64 + 1);
    	}
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    { 
    
    	FillInitialArray();
    	for(int i = 0; i < 10000000; ++i)
    		PerformSingleTest();
    	CleanArray();
    
    	return 0;
    }
    

    MemoryTesterElement.cpp:

    #include "StdAfx.h"
    #include "MemoryTesterElement.h"
    #include <assert.h>
    
    MemoryTesterElement::MemoryTesterElement(unsigned short size)
    {
    	assert(m_size == 0xcdcd);
    	assert(m_sizeCopy == 0xcdcd);
    	m_size = m_sizeCopy = size;
     	m_testMemory = new unsigned int [m_size];
    	// We fill the test memory with our pointer.
    	unsigned int ourSelves = (unsigned int)this;
    	for(int i = 0; i < m_size; ++i)
    	{
    		assert(m_testMemory[i] == 0xcdcdcdcd);
    		m_testMemory[i] = ourSelves;
    	}
    }
    
    MemoryTesterElement::~MemoryTesterElement(void)
    {	
    	assert(m_size == m_sizeCopy);
    	unsigned int ourSelves = (unsigned int)this;
    	for(int i = 0; i < m_size; ++i)
    	{
    		assert(m_testMemory[i] == ourSelves);
    	}
    	delete [] m_testMemory;
    }
    

    MemoryTesterElement.h:

    #pragma once
    
    // Class simply allocates memory and fills the array with defined values
    // that we can check if memory corruption occured.
    class MemoryTesterElement
    {
    public:
    	// The allocated memory is four times the amount of size.
    	MemoryTesterElement(unsigned short size);
    	~MemoryTesterElement(void);
    
    private:
    	// A first element 
    	unsigned short m_size;
    	// The test memory used.
    	unsigned int* m_testMemory;
    	// The size we store.
    	unsigned short m_sizeCopy;
    };
    

    BucketAdmin.cpp:

    #include "StdAfx.h"
    #include "BucketAdmin.h"
    #include <new>
    
    // this indicates the differen granularity sizes we want to use in the repsective bucket.
    const int BucketAdmin::m_bucketSizes[NUM_OF_BUCKETS] = {16, 32, 64, 128, 256};
    
    // The constructor generates the required buckets.
    BucketAdmin::BucketAdmin(void)
    {
    	// PLACE YOU IMPLEMENTATION HERE.
    	unsigned short capacity = BUCKET_CAPACITY;
    	for (int i = 0; i < NUM_OF_BUCKETS; i++) {
    		unsigned short granularity = m_bucketSizes[i];
    		m_baseMemory = (unsigned char*)malloc(sizeof(Bucket));
    		Bucket *b = new(m_baseMemory) Bucket(granularity, capacity);
    		m_buckets[i] = b;
    		//Bucket b = Bucket(granularity, capacity);
    		//m_buckets[i] = &b;
    	}
    	//delete[] m_baseMemory;
    }
    
    // Deletes all the contained buckets.
    BucketAdmin::~BucketAdmin(void)
    {
    	// PLACE YOU IMPLEMENTATION HERE.
    	for (int i = 0; i < NUM_OF_BUCKETS; i++) {
    		m_buckets[i]->~Bucket();
    		m_buckets[i] = NULL;
    	}
    }
    
    // The method tries to request memory starting fom the smallest 
    // bucket size available. If allocating memory was not possible a NULL
    // is returned.
    // capacity: The amount of memory we try to allocate.
    // returns: The pointer to the allocated memory or 
    // NULL if allocation was not possible
    void* BucketAdmin::RequestMemory(int capacity)
    {
    	// PLACE YOU IMPLEMENTATION HERE.
    	void* v;
    	for (int i = 0; i < NUM_OF_BUCKETS; i++) {
    		Bucket b = *m_buckets[i];
    		v = b.RequestMemory(capacity);
    		if (v != NULL) {
    			return v;
    		}
    	}
    	return NULL;
    }
    
    // Tries to release the memory.
    // Asks every bucket if it was in charge of the memory. 
    // A true is returned if one bucket was in charge and actually freed the memory.
    bool BucketAdmin::ReleaseMemory(void* pointer)
    {
    	// PLACE YOU IMPLEMENTATION HERE.
    	for (int i = 0; i < NUM_OF_BUCKETS; i++) {
    		Bucket b = *m_buckets[i];
    		if (b.ReleaseMemory(pointer)) {
    			return true;
    		}
    	}
    	return false;
    
    }
    

    BucketAdmin.h

    #pragma once
    #include "Bucket.h"
    
    // The general bucket administrator.
    class BucketAdmin
    {
    public:
    	// Initializes the different memory systems.
    	BucketAdmin(void);
    
    	// Releases the memory systems.
    	~BucketAdmin(void);
    
    	// Requests memory and sees what it does.
    	void* RequestMemory(int capacity);
    
    	// Tries to release the memory.
    	bool ReleaseMemory(void* pointer);
    
    private:
    
    	// The number of buckets we use.
    	enum { NUM_OF_BUCKETS = 5}; 
    	// The amount of memory chunks we can store in every Bucket.
    	enum { BUCKET_CAPACITY = 1024 };
    
    	// An array that indices in ascending order the granularity of each bucket.
    	static const int m_bucketSizes[NUM_OF_BUCKETS];
    
    	// The buckets we have here.
    	Bucket* m_buckets[NUM_OF_BUCKETS];
    
    	// A chunk of memory where we actually place the different buckets with placement news.
    	// This is to avoid calling the new and delete operators that are actually using the
    	// bucket admin.
    	unsigned char* m_baseMemory;
    
    };
    

    Bucket.cpp:

    #include "StdAfx.h"
    #include "Bucket.h"
    #include <new>
    #include <memory.h>
    
    // Initializes the bucket with the granularity and the capacity.
    // The complete memory area we can hand out later on is filled with the 
    // 0xcd pattern.
    // granularity: Indicates the size of the bucket.
    // capacity: Indicates the quantity of buckets we have.
    Bucket::Bucket(unsigned short granularity, unsigned short capacity)
    {
    	// PLACE YOU IMPLEMENTATION HERE.
    	m_bucketGranularity = granularity;
    	m_totalCapacityOfChunks = capacity;
    	m_freeChunks = (unsigned short*)malloc(capacity * sizeof(unsigned short));
    	//m_freeChunks = new unsigned short[capacity];
    	for (int i = capacity - 1; i >= 0; --i) {
    		m_freeChunks[i] = capacity - i;
    	}
    	m_numOfFreeChunks = capacity;
    	size_t s = granularity * capacity;
    	m_basePointer = (unsigned char*) malloc(s);
    	memset(m_basePointer, 0xcd, s);
    }
    
    // Tries to request a chunk of memory. Returns null if the chunkssize is
    // more than the granularity or if all contained memory portions are given away.
    // capacity: The amount of memory we try to request from the system.
    // returns: a pointer to the allocated memory chunk.
    void* Bucket::RequestMemory(int capacity)
    {
    	// PLACE YOU IMPLEMENTATION HERE.
    	if (m_numOfFreeChunks == 0) {
    		return NULL;
    	}
    	if (capacity > m_bucketGranularity) {
    		return NULL;
    	}
    	m_numOfFreeChunks--;
    	void* p = &m_basePointer[m_freeChunks[m_numOfFreeChunks]*m_bucketGranularity];
    	m_freeChunks[m_numOfFreeChunks] = -1;
    	return p;
    
    }
    
    // Tries to release the memory, if successfull it does so and returns true, otherwise it returns false.
    // The amount of memory we try to free from the system. If we free the memory we set the complete
    // content to 0xcd upfront.
    // pointer: A pointer to the memory we try to free.
    // returns: A flag whether we were actually in charge of the memory and managed to free it.
    bool Bucket::ReleaseMemory(void* pointer)
    {
    	// PLACE YOU IMPLEMENTATION HERE.
    	unsigned char* endadress = m_basePointer+m_bucketGranularity*m_totalCapacityOfChunks;
    	if (pointer < m_basePointer || pointer > endadress) {
    		return false;
    	}
    	long offset = m_basePointer - pointer;
    	if (offset % m_bucketGranularity != 0) {
    		return false;
    	}
    	memset(pointer, 0xcd, m_bucketGranularity);
    	m_numOfFreeChunks++;
    	m_freeChunks[m_numOfFreeChunks] = offset / m_bucketGranularity;
    	return true;
    }
    
    // We delete all accessed memory.
    Bucket::~Bucket(void)
    {
    	// PLACE YOU IMPLEMENTATION HERE.
    	free(m_freeChunks);
    	free(m_basePointer);
    }
    

    Bucket.h:

    #pragma once
    
    // Contains a single bucket. This is a series of memory chunks of the same size.
    class Bucket
    {
    public:
    	// Initializes the bucket with the granularity and the capacity.
    	Bucket(unsigned short granularity, unsigned short capacity);
    	~Bucket(void);
    
    	// Tries to request a chunk of memory. Returns null if the chunkssize is
    	// more than the granularity or if the bucket size is full.
    	void* RequestMemory(int capacity);
    	// Tries to release the memory, if successfull it does so and returns true, otherwise it returns false.
    	bool ReleaseMemory(void* pointer);
    
    private:
    	// The base pointer of the system. 
    	// This is the memory where all memory chunks are contained in.
    	unsigned char* m_basePointer;
    	// The list with the free buckets we have.
    	// It contains the indices of memory chunks that are available for allocation.
    	unsigned short* m_freeChunks;
    	// The capacity in free buckets we have.
    	// It basically indicates how many items are stored in the array m_freeBuckets.
    	unsigned short m_numOfFreeChunks;
    	// The total capacity in buckets we have.
    	// This is the total length of items the array of 
    	unsigned short m_totalCapacityOfChunks;
    	// The amount of bytes a bucket entry contains.
    	unsigned short m_bucketGranularity;
    
    };
    

    stdafx.h:

    // stdafx.h : include file for standard system include files,
    // or project specific include files that are used frequently, but
    // are changed infrequently
    //
    
    #pragma once
    
    #include "targetver.h"
    
    #include <stdio.h>
    #include <tchar.h>
    
    // TODO: reference additional headers your program requires here
    

    targetver.h:

    #pragma once
    
    // Including SDKDDKVer.h defines the highest available Windows platform.
    
    // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
    // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
    
    #include <SDKDDKVer.h>
    

    Danke - Enomine



  • Und entschuldigung dass es so ein langer code ist. Es ist eben eine in sich geschlossene Aufgabe und ich sehe da keine kürzungsmöglichkeit.

    Aufgabe ist ja u.a. den Speicher mit 0xcd zu initialidsieren. Der new operator wird überschrieben. In zeile 24 und 63 vom Bucket setze ich über memset den Speicher auf 0xcd. Möglicherweise unzureichend.

    Mir stellt sich die Frage ob der new operator auch für zeile 71 und 97 in BucketSystem überschrieben ist.

    Danke - Enomine


  • Mod

    Enomine schrieb:

    Bei der Ausführung führt Zeile 8 "assert(m_size == 0xcdcd);" in MemoryTesterElement zu einer Ausnahme.
    Bisher habe ich noch nicht verstanden warum. Dies war vorgegebener Code vom Professor und da das Objekt hier erst erstellt wird dürfte der Inhalt von m_size ja random sein.

    Das ist undfiniertes Verhalten. Das assert verlässt sich darauf, dass sich der Inhalt des Speicherbereichs, in dem das jeweilige MemoryTesterElement lebt, seit der Allokation (dort wird der Bereich ja mit 0xcd überschrieben) nicht geändert hat und dass der Wert von m_size von diesem Inhalt abhängt, was aber nicht der Fall ist.

    Enomine schrieb:

    Mir stellt sich die Frage ob der new operator auch für zeile 71 und 97 in BucketSystem überschrieben ist.

    Dort wird placement-new verwendet.



  • Wenn Ihr Programm fehlerfrei und ohne assertations durchläuft haben Sie Ihre erste Speicherverwaltung geschrieben. Wenn Sie jetzt in der Datei BucketSystem in den beiden new Routinen jeweils die erste Zeile auskommentieren und die zweite Zeile einkommentieren, verwenden Sie für alle Speicheranforderungen wieder das Standard malloc. Auf meinem Rechner ist die Variante mit dem eigenen Bucket Memory Manager gut doppelt so schnell.

    Kann das hier jemand verifizieren? Für mich klingt es erstmal Zweifelhaft, dass ein eigener "new" operator eine Performance Vorteil von 100% bringt. Sonst muss ich da am Wochenende mal was rumprobieren.



  • camper schrieb:

    Enomine schrieb:

    Bei der Ausführung führt Zeile 8 "assert(m_size == 0xcdcd);" in MemoryTesterElement zu einer Ausnahme.
    Bisher habe ich noch nicht verstanden warum. Dies war vorgegebener Code vom Professor und da das Objekt hier erst erstellt wird dürfte der Inhalt von m_size ja random sein.

    Das ist undfiniertes Verhalten. Das assert verlässt sich darauf, dass sich der Inhalt des Speicherbereichs, in dem das jeweilige MemoryTesterElement lebt, seit der Allokation (dort wird der Bereich ja mit 0xcd überschrieben) nicht geändert hat und dass der Wert von m_size von diesem Inhalt abhängt, was aber nicht der Fall ist.

    Möchtest du mir damit sagen, dass der Speicherbereich, in welchem MemoryTesterElement lebt tatsächlich mit 0xcd überschrieben ist, jedoch m_size außerhalb liegt? Hört sich für mich irgendwie unlogisch an xD Könntest du das näher erklären? Siehst du hier einen Programmierfehler von mir? Kann mir so schlecht vorstellen, dass es ein Denkfehler meines Professors ist.

    camper schrieb:

    Enomine schrieb:

    Mir stellt sich die Frage ob der new operator auch für zeile 71 und 97 in BucketSystem überschrieben ist.

    Dort wird placement-new verwendet.

    Könntest du mir dies bitte erklären? Nach den Vorlesungsunterlagen, Seite 20 wird dabei hinter dem "new" direkt eine Klammer gesetzt. Dies ist in Zeile 71 und 97 gar nicht der Fall. Deswegen sah ich es als normales new an. Die Frage war ob nun schon das Überladene benutzt wird und er versucht über meinen Speichermanager zu gehen oder ob es es einfach vom Heap holt.

    Danke - Enomine



  • Schlangenmensch schrieb:

    [...] Auf meinem Rechner ist die Variante mit dem eigenen Bucket Memory Manager gut doppelt so schnell.

    Kann das hier jemand verifizieren? Für mich klingt es erstmal Zweifelhaft, dass ein eigener "new" operator eine Performance Vorteil von 100% bringt. Sonst muss ich da am Wochenende mal was rumprobieren.

    Darfst du gern. Kannst ja mal selbst die Aufgabe lösen xD Gern höre dir die Vorlesung mal an.

    Danke - Enomine


  • Mod

    Enomine schrieb:

    Möchtest du mir damit sagen, dass der Speicherbereich [...] mit 0xcd überschrieben ist, jedoch m_size außerhalb liegt?

    Nein.
    Bevor das MemoryTesterElement and der jeweiligen Speicherstelle entstanden ist, befindet sich dort nur roher Speicher (d.h. man kann man als Array aus (unsigned) char) betrachten). Wenn dann im Konstruktor auf den gespeicherten Wert an der Stelle m_size zugegriffen wird, wird also tatsächlich auf die gespeicherten einzelnen char-Werte zugegriffen, der Typ des Ausdrucks ist aber nicht (unsigned) char sondern unsigned short; und diese Art von Aliasing ist verboten.

    Ob das tatsächlich die Ursache für das Fehlschlagen des assert ist, kann ich nicht beurteilen. Der Author macht sich ohne Not von 32-bit Windows abhängig, obwohl das Programm eigentlich keinerlei OS-spezifische Funktionalitäten nutzt.



  • Enomine schrieb:

    Die Frage war ob nun schon das Überladene benutzt wird und er versucht über meinen Speichermanager zu gehen oder ob es es einfach vom Heap holt.

    Das könntest du z.B. mit einem Debugger recht einfach selbst heraus finden. Oder mit aussagekräftigen Debug Ausgaben 😉



  • Hey ihr zwei,

    wie würdet ihr denn nun vorgehen, um die Aufgabenstellung zu erfüllen. Da ich in knapp 3 Wochen Drittversuch in der Klausur habe, ist es mir wichtiger die Aufgabenstellung zu erfüllen und zu verifizieren, dass MEIN Code okay ist, anstatt über mögliche "bessere" Verhaltensweisen meines Professors beim Programmieren, zu sprechen.

    Findet ihr, dass meine Implementierungen von Bucket.cpp und BucketAdmin.cpp korrekt sind? Die Klassen waren bis auf die Methodenrümpfe und Kommentare leer.

    Welche konkreten Schritte muss ich denn nun unternehmen, um das Programm "fehlerfrei und ohne assertations" zu bekommen?

    Bezüglich des Debuggens: Ich habe schon etwas rumgerätzelt mit dem Debugger, kann aber noch nicht sagen ob ich den richtigen Einsprungspunkt gefunden habe. Denn es werden ja bereits arbeiten erledigt, bevor die main aufgerufen wird. So wird die Zeile 12 "BucketAdmin m_memoryManager;" ja ausgeführt bevor die main startet. So habe ich es jedenfalls verstanden.
    Wie kann ich den Debugger so starten, dass er bei der aller ersten Anweisung direkt stoppt?

    Ich verfüge über Teamviewer und Skype. Möchtet ihr mir in einer solchen Konferenz mal über die Schulter schauen?

    Danke - Enomine



  • Ich muss verstanden haben wie man sein eigenes Speicherverwaltungssystem aufbauen kann über die Bucket-Strategie. Seht ihr das anhand meiner Implementierungen gegeben? Würdet ihr die Implementierungen also korrekt ansehen? Was muss ich tun, damit die Implementierungen auch mit dem vorgegebenen Code meines Professors zusammen funktionieren?

    Danke - Enomine



  • Ich habe im Moment keinen eigenen Rechner, der über Skype oder Teamviewer verfügt. Das ist auch nicht unbedingt nötig, denke ich.

    Ansonsten, habe ich grade in diesem Thread wenig gelesen, was Verbesserungen bzgl. der Vorgabe betrifft.

    Tipp fürs Debugging:
    Breakepoint in dein new(), und den Callstack anschauen um zu prüfen von wo aus es aufgerufen wird.
    Wahlweise: Breakpoint in den else Teil von "PerformeSingleTest". Von da aus in den new rein "steppen".
    Wenn du den Constructor von BucketAdmin debuggen willst, setz ein Breakpoint da rein.

    Ich habe in meinen Anfängen viele Ausgaben benutzt um Sachen zu Debuggen.
    Zum Beispiel in dein new() ein std::cout << "In my new overload" << "\n";, dass ist nicht schön, aber kann einem unter Zeitdruck manchmal schneller helfen, als sich noch in die Welt der Debugger einzuarbeiten.

    Camper hat geschrieben, dass sich der Autor von 32-Bit Systemen abhängig macht. Mit was für Einstellungen und auf was für einem System kompilierst du?

    Sry, aber der Misch aus malloc, new, memset usw. ist nichts, wo ich beim drüber lesen zu 100% sagen kann, "ja das passt so", dafür gibt es einfach zu viele Fallstricke.

    Edit:
    Was mir grade auffällt, hier:

    void* result = m_memoryManager.RequestMemory(size); 
         // void* result = NULL; 
         if (!result) 
         {   
             result = malloc(size); 
             // We fill the memory with the test pattern here to comply 
             // with the default that all memory is initialized with 0xcd. 
             memset(result, 0xcd, size); 
         }
    

    memset wird nur aufgerufen, wenn result ein nullpointer ist und sonst beschreibst deinen Speicherbereich überhaupt nicht mit dem verlangten Muster.

    Edit2: Das scheinst du im Konstruktor von Bucket zu versuchen... Für dich zur Infor, bei mir schlägt die Assertion auch Fehl, mit dem Vergleich 5 == 52685

    Edit 3: Nicht 5, sondern 0 == 52685



  • Schlangenmensch schrieb:

    [...]Ansonsten, habe ich grade in diesem Thread wenig gelesen, was Verbesserungen bzgl. der Vorgabe betrifft.

    Das ist ja das Problem 😉 Ich weiß nicht wie ich die assertion weg bekomme 😉

    [...]Camper hat geschrieben, dass sich der Autor von 32-Bit Systemen abhängig macht. Mit was für Einstellungen und auf was für einem System kompilierst du?

    Windows 7 64 Bit. Visual Studio 2017. Windows SDK Version 10.0.15063.0

    Sry, aber der Misch aus malloc, new, memset usw. ist nichts, wo ich beim drüber lesen zu 100% sagen kann, "ja das passt so", dafür gibt es einfach zu viele Fallstricke.

    Ja die Frage war tatsächlich auch nicht als kurzes drübersehen gemeint 😉 Ich weiß dass ihr ja alle Freizeit hier verbringt.
    Jedenfalls hatte ich deswegen die Aufgabe auch direkt als Projekt hochgeladen, damit man selbst rumprobieren kann. Ich persönlich mag das nicht wenn ich jemanden in Java helfe und der kein Projekt zur Verfügung stellt sondern nur Code.
    Deswegen schlage ich dies vor:

    Schlangenmensch schrieb:

    [...]Sonst muss ich da am Wochenende mal was rumprobieren.

    😉

    memset wird nur aufgerufen, wenn result ein nullpointer ist und sonst beschreibst deinen Speicherbereich überhaupt nicht mit dem verlangten Muster.
    Edit2: Das scheinst du im Konstruktor von Bucket zu versuchen... Für dich zur Infor, bei mir schlägt die Assertion auch Fehl, mit dem Vergleich 5 == 52685

    Hatte versucht 2x darauf hinzuweisen, dass von mir nur Bucket.cpp und BucketAdmin.cpp programmiert wurden und der Rest vom Professor vorgegeben ist, dort also auch keine Änderungen zu machen sind.

    Die if-Abfrage funktioniert so, dass wenn Bucket.cpp und BucketAdmin.cpp noch nicht ausprogrammiert sind, dass diese NULL zurück geben und dann der standard-Windows-Speicherverwalter benutzt wird. Wenn Bucket.cpp und BucketAdmin.cpp korrekt ausprogrammiert sind, dann merkt der das an der Stelle und benutzt den gerade programmierten Speicherverwalter. Die Aussage ist es ja dann, dass der Eigene schneller Arbeitet, als der von Windows. In der Aufgabenstellung ist auch angegeben, dass man da die erste Zeile auskommentieren und die zweite einkommentieren soll, um den ursprungszustand wieder herzustellen.

    Danke - Enomine



  • Schlangenmensch schrieb:

    Edit 3: Nicht 5, sondern 0 == 52685

    0 ist niemals gleich 52685 😉

    Danke - Enomine



  • In BucketAdmin::RequestMemory erstellst du mit

    Bucket b = *m_buckets[i];
    

    Eine Kopie, bei der der Destruktur beim Verlassen aufgerufen wird. In ReleaseMemory ebenso.
    Das Projekt habe ich mir aber nicht runtergeladen, Speicherverwaltung ist Arbeit, noch dazu keine schöne...

    Bucket* b = m_buckets[i];
    

    Ist das gemeint?


  • Mod

    void* operator new(unsigned int size)
    

    Der Standard schreibt für den ersten Parameter zwingend std::size_t vor. Falls das Programm nicht für 32bit compiliert wird, wird diese zusätzliche Überladung möglicherweise still nicht genutzt.


Anmelden zum Antworten