Die Frage, ob überprüft werden muss, welche Renditen erzielt werden, mallocist umstritten und führt immer zu heftigen Diskussionen.
Einige Leute denken, dass wir versuchen sollten, alle Arten von Laufzeitfehlern zu behandeln, einschließlich. und OOM-Situationen. Andere glauben, dass mit OOM noch wenig getan werden kann und es besser ist, die Anwendung abstürzen zu lassen. Auf der Seite der zweiten Personengruppe gibt es auch die Tatsache, dass die zusätzliche OOM-Verarbeitungslogik schwer zu testen ist. Und wenn der Code nicht getestet wird, funktioniert er mit ziemlicher Sicherheit nicht.
Ich stimme voll und ganz zu, dass Sie keine Fehlerbehandlungslogik implementieren sollten, die Sie nicht testen werden. Es wird mit ziemlicher Sicherheit nichts verbessern und vielleicht sogar noch schlimmer - alles ruinieren.
Die Frage, ob versucht werden soll, mit OOM-Situationen in Bibliotheken / Anwendungen umzugehen, ist umstritten und wird hier nicht angesprochen. Im Rahmen dieser Veröffentlichung möchte ich nur meine Erfahrungen darüber teilen, wie Sie die implementierte Logik für den Umgang mit OOM-Situationen in in C / C ++ geschriebenen Anwendungen testen können. Das Gespräch wird über Linux- und MacOS-Betriebssysteme geführt. Aus einer Reihe von Gründen wird Windows umgangen.
Einführung
Wir alle wünschen uns, dass OOM nie passiert ist, aber im wirklichen Leben ist dies aus folgenden Gründen nicht immer möglich:
- RAM ist immer begrenzt.
- SWAP ist nicht immer aktiviert.
- Anwendungen verhalten sich nicht immer angemessen und versuchen manchmal, unrealistisch große Speichermengen zuzuweisen, wodurch sie sich selbst und andere stören.
- Es gibt noch 32-Bit-Anwendungen.
- Overcommit ist nicht immer aktiviert.
- Der Speicherverbrauch kann beispielsweise begrenzt werden
ulimit. -
LD_PRELOAD.
, , , OOM . , , :
- , - .
- OOM . .
- . , .
, , SQLite. , . . SQLite .
, , , . OOM Killer, , . , C++, .
1.
, OOM . my_malloc my_free malloc free.
my_free . my_realloc.
my_malloc malloc . my_malloc , NULL .
, :
- 3rd party .
-
malloc. -strdup. -
malloc’ , , . - C++
mallocfree.
- .
2.
Linux LD_PRELOAD. . malloc. , malloc/realloc/free (weak). , macOS LD_PRELOAD, DYLD_INSERT_LIBRARIES.
, , LD_PRELOAD DYLD_INSERT_LIBRARIES malloc/realloc NULL .
, "" . , .
, "" , , . :
-
main. , . - Runtime macOS " ". , , , .
-
printfmacOSSIGSEGV/SIGBUS. - ,
std::bad_alloc, . , , , OOM.std::terminate. . -
std::threadstd::terminatemacOS.
UPDATE: Travis CI , macOS / Xcode , std::bad_alloc , std::thread std::terminate.
Overthrower. - malloc NULL. Overthrower - , .
3.
main
, main , main runtime . main, , .. - main.
, main . Overthrower, OOM . Overthrower , .
:
activateOverthrowerdeactivateOverthrower
:
#ifdef __cplusplus
extern "C" {
#endif
void activateOverthrower() __attribute__((weak));
unsigned int deactivateOverthrower() __attribute__((weak));
#ifdef __cplusplus
}
#endif
Overthrower LD_PRELOAD, NULL, , .
, , :
int main(int argc, char** argv)
{
activateOverthrower();
// Some code we want to test ...
deactivateOverthrower();
}
activateOverthrower/deactivateOverthrower , :
TEST(Foo, Bar)
{
activateOverthrower();
// Some code we want to test ...
deactivateOverthrower();
}
, -, , Overthrower , :
#ifdef __cplusplus
extern "C" {
#endif
void pauseOverthrower(unsigned int duration) __attribute__((weak));
void resumeOverthrower() __attribute__((weak));
#ifdef __cplusplus
}
#endif
:
TEST(Foo, Bar)
{
activateOverthrower();
// Some code we want to test ...
pauseOverthrower(0);
// Some fragile code we can not fix ...
resumeOverthrower();
// Some code we want to test ...
deactivateOverthrower();
}
__cxa_allocate_exception, , , malloc, NULL. , Linux, malloc, __cxa_allocate_exception (emergency buffer), , . .
macOS , , , , std::bad_alloc, std::terminate.
UPDATE: , macOS / Xcode .
, , , __cxa_allocate_exception malloc. - Overthrower’ malloc. Overthrower malloc __cxa_allocate_exception.
, , , macOS __cxa_atexit, Linux dlerror. .
Overthrower , malloc free. Overthrower’ , activateOverthrower deactivateOverthrower , :
overthrower got deactivation signal.
overthrower will not fail allocations anymore.
overthrower has detected not freed memory blocks with following addresses:
0x0000000000dd1e70 - 2 - 128
0x0000000000dd1de0 - 1 - 128
0x0000000000dd1030 - 0 - 128
^^^^^^^^^^^^^^^^^^ | ^^^^^^ | ^^^^^^^^^^
pointer | malloc | block size
|invocation|
| number |
Overthrower , , .
Overthrower’, , valgrind. , OOM. , , Overthrower . Overthrower , , deactivateOverthrower , stderr .
Overthrower 3 :
- Random —
rand() % duty_cycle == 0.duty_cycle, . - Step — (
malloc_seq_num >= delay),delay.
<--- delay --->
--------------+
|
| All further allocations fail
|
+------------------------------
- Pulse — (
malloc_seq_num > delay && malloc_seq_num <= delay + duration),delayduration.
<--- delay --->
--------------+ +------------------------------
| |
| | All further allocations pass
| |
+----------------+
<--- duration --->
:
OVERTHROWER_STRATEGYOVERTHROWER_SEEDOVERTHROWER_DUTY_CYCLEOVERTHROWER_DELAYOVERTHROWER_DURATION
activateOverthrower. , Overthrower , /dev/urandom.
- Overthrower
malloc/. - .
- Overthrower .
- Overthrower .
- Overthrower , .
- Overthrower’ .
- Overthrower Overthrower-aware . , .
- Overthrower selbst wird unter Ubuntu (seit 14.04) und macOS (seit Sierra (10.12) und Xcode 8.3) getestet. Während des Tests versucht Overthrower unter anderem, sich fallen zu lassen.
- Wenn ein echtes OOM im System erscheint, tut Overthrower alles, um nicht selbst zu fallen.