RejectedSoftware Forums

Sign up

InvalidMemoryOperation when using a Timer as a class member

Hi all,

Does anybody have any ideas on this one?

Take a new vibe.d project. Put this in the app.d and run unittests. It gets through the tests but it seems when things are torn down there is a core.exception.InvalidMemoryOperationError.

class InternalTimer {
    this() {
        _timer = setTimer(1.seconds, () {});
    }
private:
    Timer _timer;
}

unittest {
    auto t = new InternalTimer;
}

I can't get a stack trace from gdb on it either. And this only occurs when it's a class member. If I create a timer as a local variable in the constructor (which isn't helpful to me) the error does not occur.

Any ideas?

Re: InvalidMemoryOperation when using a Timer as a class member

On Tue, 03 Feb 2015 02:31:01 GMT, David Monagle wrote:

Hi all,

Does anybody have any ideas on this one?

Take a new vibe.d project. Put this in the app.d and run unittests. It gets through the tests but it seems when things are torn down there is a core.exception.InvalidMemoryOperationError.

class InternalTimer {
    this() {
        _timer = setTimer(1.seconds, () {});
    }
private:
    Timer _timer;
}

unittest {
    auto t = new InternalTimer;
}

I can't get a stack trace from gdb on it either. And this only occurs when it's a class member. If I create a timer as a local variable in the constructor (which isn't helpful to me) the error does not occur.

Any ideas?

The problem is that Timer.~this() internally calls releaseTimer() of the event driver, which in turn modifies some internal structures. These structures may in turn reallocate or free some memory, which causes the InvalidMemoryOperationError (it's thrown whenever the GC gets accessed during a collection). So to avoid this error it is necessary to explicitly clear the _timer field before the finalizer gets run, for example using a separate "dispose" method:

class InternalTimer {
    private Timer _timer;
    this() { _timer = setTimer(1.seconds, () {}); }
    void dispose() { _timer = Timer.init; }
    // or: destroy(_timer);
}

unittest {
    auto t = new InternalTimer;
    t.dispose();
}

BTW, this one is definitely one of my pet peeves of the current GC implementation. It's very hard to debug due to missing stack traces and extremely easy to run into. On the other hand it's always dangerous to access any GC allocated memory within a finalizer anyway, because there is no guaranteed order of destruction. So using an explicit destruction scheme is necessary in many cases anyway, even without an InvalidMemoryOperationError.

Re: InvalidMemoryOperation when using a Timer as a class member

Turns out the cause was slightly different. Fixed now.

See also #978