Am 11.05.2011 17:36, schrieb Andi Vajda:
>> As you can clearly see, the JNIEnv_ instance is a NULL pointer. Contrary
>> to my initial assumption, the thread doesn't have a JCC thread local
>> object. Since any thread may trigger a GC collect run, and not just
>> threads, that use JCC, this looks like a bug in JCC to me.
> 
> Any thread that is going to call into the JVM must call attachCurrentThread() 
> first. This includes a thread doing GC of object wrapping java refs which it 
> is going to delete.

I'm well aware of requirement to call attachCurrentThread() in every
thread that uses wrapped objects. This segfault is not caused by passing
JVM objects between threads explicitly. It's Python's cyclic GC that
breaks and collects reference cyclic with JVM objects in random threads.

Something in Python 2.7's gc must have been altered to increase the
chance, that a cyclic GC collect run is started inside a thread that
isn't attached to the JVM. As far as I know the implementation of
Python's cyclic GC detection, it's not possible to restrict the cyclic
GC to some threads. So any unattached thread that creates objects, that
are allocated with _PyObject_GC_New(), has a chance to trigger the
segfault. Almost all Python objects are using _PyObject_GC_New(). Only
very simple types like str, int, that can't reference other objects, are
not tracked. Everything else (including bound methods of simple types)
is tracked.

In a few words: Any unattached thread has the chance to crash the
interpreter unless the code is very, very limited. This can be easily
reproduced with a small script:

---
import lucene
import threading
import time
import gc

lucene.initVM()

def alloc():
    while 1:
        gc.collect()
        time.sleep(0.011)

t = threading.Thread(target=alloc)
t.daemon = True

t.start()

while 1:
    obj = {}
    # create cycle
    obj["obj"] = obj
    obj["jcc"] = lucene.JArray('object')(1, lucene.File)
    time.sleep(0.001)

---

I wonder, why it wasn't noticed earlier.

Christian

Reply via email to