|
35 | 35 | it will never be since the specific Thread is dead... Also if this dead Thread remains in |
36 | 36 | the _limbo dictionary (small inconsistency since it will be return in case of threading.enumarate()). |
37 | 37 |
|
38 | | -When the thread is killed inside before `_started.set()`, we always get this weird error message: |
| 38 | +When the thread is killed inside before `_started.set()`, we always get a weird error message: |
39 | 39 | "Exception ignored in thread started by: <A method>" |
40 | 40 | This comes from the `thread_run` (C code) calling `_PyErr_WriteUnraisableMsg` |
41 | | -At first glance, it seems that the ignored Exception is a MemoryError that skip part of the `_bootstrap_inner` method |
| 41 | +At first glance, it seems that the ignored Exception is a MemoryError that happens before or that |
| 42 | +the beginning of the `_bootstrap_inner` method (before `_started.set()` obviously). |
| 43 | +If we put sys.unraisablehook to get more information, it is always due to a MemoryError: |
| 44 | +
|
| 45 | +--- Unraisable Exception Caught --- |
| 46 | +Full Traceback: |
| 47 | +Traceback (most recent call last): |
| 48 | + File "/home/odoo/Documents/Pythons/py12/lib/python3.12/threading.py", line 1062, in _bootstrap_inner |
| 49 | + File "/home/odoo/Documents/Pythons/py12/lib/python3.12/threading.py", line 1051, in _set_tstate_lock |
| 50 | + self._tstate_lock = _set_sentinel() |
| 51 | + ^^^^^^^^^^^^^^^ |
| 52 | +RuntimeError: can't allocate lock |
| 53 | +------------------------------------ |
| 54 | +Most of the case, Python cannot call the hook at all since it needs some memory to do so and then terminated |
| 55 | +with a error like this: Exception ignored in sys.unraisablehook: <function bulletproof_unraisable_hook at 0x7d87eff923e0> |
| 56 | +
|
| 57 | +Note that we also get a traceback from inside _bootstrap_inner if the memory exaustion happens inside of it: |
| 58 | +Traceback (most recent call last): |
| 59 | + File "/home/odoo/Documents/Pythons/py12/lib/python3.12/threading.py", line 1033, in _bootstrap |
| 60 | + self._bootstrap_inner() |
| 61 | + File "/home/odoo/Documents/Pythons/py12/lib/python3.12/threading.py", line 1080, in _bootstrap_inner |
| 62 | + self._delete() |
| 63 | + File "/home/odoo/Documents/Pythons/py12/lib/python3.12/threading.py", line 1112, in _delete |
| 64 | + del _active[get_ident()] |
| 65 | + ~~~~~~~^^^^^^^^^^^^^ |
| 66 | +KeyError: 139703676303040 |
| 67 | +=> Make sense since the thread isn't inside the active at this point. |
| 68 | +
|
42 | 69 |
|
43 | | -What we tried: |
| 70 | +Other try: |
44 | 71 | - Increasing the stack_size to force Python to only accept create new Thread when more |
45 | 72 | memory is available on the stack. That's doesn't seems to work even with a hug number... |
46 | 73 | Does this method even work ?? Signature is odd and the doc is incomplete ?? |
| 74 | +=> Stack memory isn't the Problem. Heap memory is ... |
47 | 75 |
|
48 | 76 | - Catch the MemoryError, to sleep + gc after in order to force free memory => doesn't work better |
49 | 77 |
|
|
80 | 108 |
|
81 | 109 | TODO: |
82 | 110 | - Check inside the ignored Exception with a debugger C |
83 | | -- Check works stack_size |
84 | | -- |
85 | 111 |
|
86 | 112 | """ |
87 | | -threading.stack_size(33000) |
88 | 113 |
|
89 | | -print("PID: ", os.getpid(), " Stack Size ", threading.stack_size()) |
| 114 | +def unraisable_hook(unraisable): |
| 115 | + # This part might fail under memory exhaustion |
| 116 | + tb_str = "".join(traceback.format_exception( |
| 117 | + unraisable.exc_type, unraisable.exc_value, unraisable.exc_traceback |
| 118 | + )) |
| 119 | + print(f""" |
| 120 | +--- Unraisable Exception Caught --- |
| 121 | +Object: {unraisable.object} |
| 122 | +Full Traceback:{tb_str} |
| 123 | +-----------------------------------""") |
| 124 | + |
| 125 | +# Set hook to have more detail |
| 126 | +sys.unraisablehook = unraisable_hook |
| 127 | + |
| 128 | +# Set limit to avoid crash my computer :D |
| 129 | +resource.setrlimit(resource.RLIMIT_AS, (1_000_000_000, 1_500_000_000)) |
90 | 130 |
|
| 131 | +print("PID: ", os.getpid(), " Stack Size ", threading.stack_size()) |
91 | 132 | # print("Sleep 10 sec") |
92 | 133 | # time.sleep(10) |
93 | 134 |
|
94 | | -resource.setrlimit(resource.RLIMIT_AS, (1_000_000_000, 1_500_000_000)) |
95 | | - |
96 | 135 | def memory_error(): |
97 | 136 | memory_issue_list = [] |
98 | 137 | while True: |
|
0 commit comments