Hi!
I have a crash / error and I’m assuming my mental model of threads and the garbage collector is missing something. I’ve read everything I can find but the docs are a bit brief on the topic and I haven’t got a clear picture. Can someone help me understand what’s happening?
Edit: Actually the program dies with a much shorter piece of code than I originally posted. It’s so simple now I’m wondering is this a bug in hxcpp?
class Main {
public static function looper_thread() {
trace ('thread start');
while (true)
trace (haxe.Timer.stamp());
}
public static function main () {
cpp.vm.Thread.create (looper_thread);
while (true)
cpp.vm.Gc.run(true);
}
}
I’d expect it to print the time endlessly, but within a couple of minutes the program dies silently.
– The remainder of the original post below –
I shortened the problem down to the code below - I have a buffer that is created and accessed with raw c++. It’s allocated once in the main thread and repeatedly accessed from a separate thread after that.
Here’s some things that I think are true about this code. Which of these are wrong ? -
- The garbage collector runs in the main thread.
- I need to call
Gc.safePoint
because the child thread doesn’t allocate and so if the collector runs it would deadlock trying to “stop the world”. - The collector can’t see the pointer *data because it’s not on the stack and the collector doesn’t follow arbitrary class data.
-
Buffer.finalizer
is never called, which seems correct (the referenceMain.buffer
stays in scope) - As a result,
buffer->data
should be safe to access. - Even if the gc does compaction (I dunno if that’s enabled), it should still be safe to access
buffer->data
as that isn’t part of the collected memory and won’t be moved.
Compile command and example run:
haxe -main Main -cpp bin
bin\Main.exe
Main.hx:46: hi
Main.hx:25: thread start
Main.hx:29: 0
Main.hx:29: 1
Main.hx:29: 2
Main.hx:29: 3
Main.hx:29: 4
Main.hx:29: 5
Critical Error: Bad Allocation while collecting - from finalizer?
Tested on Haxe 4-rc1, compiled to VS2017. Also same behaviour on Haxe 3.4.7. It’s random how far it gets before the error. Sometimes there’s no error message it just dies silently.
// Main.hx
@:headerClassCode('int *data;')
class Buffer extends cpp.Finalizable {
public function new () {
super();
init();
}
private function init() {
untyped __cpp__ ('this->data = new int[1000]');
untyped __cpp__ ('for (int i = 0; i < 1000; i ++) this->data[i] = i');
}
override function finalize() {
trace ('Uhoh I got deleted that is NO GOOD');
untyped __cpp__ ('delete[] this->data');
}
}
class Main {
var buffer : Buffer;
public function looper_thread() {
trace ('thread start');
while (true) {
for (i in 0...1000) {
var x : Int = untyped __cpp__('this->buffer->data[{0}]', i);
trace (x);
cpp.vm.Gc.safePoint();
}
}
}
public function new () {
buffer = new Buffer();
cpp.vm.Thread.create (looper_thread);
while (true) {
// This induces the crash much faster,
// but if we did nothing eventually the gc would run and crash anyway
cpp.vm.Gc.run(true);
}
}
public static function main () {
trace ('hi');
new Main ();
}
}