Suspected memory management problem when constantly removing and adding to a vector of ofPolylines


#1

Hi guys,

I’m still very much an amateur when it comes to c++ and especially memory management concepts.

I’m currently working on an audio-responsive piece where i have to add a new element to a vector of ofPolyline’s while at the same time removing an element, every time i receive some audio input.

//--------------------------------------------------------------
//Audio input
void ofApp::audioReceived(float *input, int bufferSize, int nChannels )
{
    float peak = 0;
    
    //If recording is enabled by the user,
    //then store received data
    for (int i=0; i<bufferSize; i++) {
        buffer[ recPos ] = input[i];
        recPos++;
        //When the end of buffer is reached, recPos sets
        //to 0, so we record sound in a loop
        recPos %= N;
        
        if (input[i] > peak) {
            peak = input[i];
        }
    }
    
    if (peak > alltimePeak) {
        alltimePeak = peak;
    }
    
    previosPeak = currentPeak;
    currentPeak = peak;
    
    ofPolyline line = ofPolyline();
    float times = 100;
    float firstY = 0;
    float deg = float(360)/times;
    int maxRad = -ofGetHeight() * currentPeak * 3;

    line.clear();
    line.begin();
    for (int j = 0; j < times; j++) {
        line.rotateDeg(deg, glm::vec3(0,0,1));
        int index = ofMap(j, 0, times, 0, buffer.size() - 1);
        float testY = ofMap(buffer[index], -1, 1, -maxRad, maxRad * 2);
        line.addVertex(0, testY);
        
    }
    line.end();
    
    trail.push_back(line);
    trail.erase(trail.begin());
    
}

This is what my draw function looks like:

void ofApp::draw(){    
    ofBackground(0,0);
    ofSetLineWidth(3);
    
    ofPushMatrix();
    ofTranslate(ofGetWidth()/4, ofGetHeight() * 3/4);
    ofRotateYDeg(-40);
    ofSetColor(255,150);
    float time = ofGetElapsedTimef();
    

    for (int i = trail.size() - 1; i >= 0; i--) {
        
        float z = ofMap(i, trail.size() -1, 0, 0, 200);
        float scale = 5000;
        float soundDist = ofMap(sin((i * 0.01)), -1, 1, 0, currentPeak * scale);
        
        if (abs(soundDist) <= 100) {
            ofLogWarning("soundD", ofToString(soundDist));
            soundDist = 0;
        }
        
        float sinMov = ofMap(sin((i * 0.08) + time), -1, 1, 0, -200 - soundDist);

        ofTranslate(0, 0, -z);
        ofPushMatrix();
        ofTranslate(0, sinMov);
        trail[i].draw();
        ofPopMatrix();
    }
    
    ofPopMatrix();
}

This is my setup function:

//--------------------------------------------------------------
void ofApp::setup(){
    ofEnableAlphaBlending();
    ofBackground(34, 34, 34);
    ofSetFrameRate(60);

    //Set buffer size and fill it by zeros
    buffer.resize( N, 0.0 );
    
    //Start the sound output in stereo (2 channels)
    //and sound input in mono (1 channel)
    soundStream.setup( this, 2, 1, sampleRate, 256, 4 );    
    
    //SETUP TRAIL
    for (int i = 0; i < trailSize; i++) {
        ofPolyline p = ofPolyline();
        trail.push_back(p);
    }
    
    
}

Whenever i run my code it works fine until a certain point where it crashes an I have an error in this function:

void ofGLRenderer::draw(const ofPolyline & poly) const{
	if(!poly.getVertices().empty()) {
		// use smoothness, if requested:
		if (currentStyle.smoothing) const_cast<ofGLRenderer*>(this)->startSmoothing();

		glEnableClientState(GL_VERTEX_ARRAY);
		glVertexPointer(3, GL_FLOAT, sizeof(glm::vec3), &poly.getVertices()[0].x);
		glDrawArrays(poly.isClosed()?GL_LINE_LOOP:GL_LINE_STRIP, 0, poly.size());        //Thread 1: EXC_BAD_ACCESS (code=1, address=0x8)

		// use smoothness, if requested:
		if (currentStyle.smoothing) const_cast<ofGLRenderer*>(this)->endSmoothing();
	}
}

I’m assuming with such a dynamic and constantly modified vector I should definitely have methods to manage memory allocation but I still pretty sucky at c++ and fully understanding memory management. Would really appreciate some help!


#2

no, that should be ok, as long as you don’t use raw pointers in c++ memory is deleted when objects go out of scope automatically.

vectors are not very good at deleting from the beginning so you might want to change trail from a vector to a deque but memory in contiguous positions as in a vector will make things faster so it’s probably not even worth. In any case if you don’t have any performance problems don’t worry about it

one thing that could be potentially problematic is that you are accessing the same vector (trails) from the audio and graphics thread and allocating new memory when pushing back and erasing elements which could potentially crash the application. You might want to use an ofMutex to lock when the application is drawing so the audio thread doesn’t add new lines simultaneously or use an ofThreadChannel to send data from the audio to the graphics thread so the trails vector is only modified in one thread


#3

thanks so much for the speedy response!

I’ll look into the usage of ofMutex and ofThreadChannel.