Pertanyaan tentang apakah perlu memeriksa pengembalian apa mallocyang kontroversial dan selalu menimbulkan diskusi panas.
Beberapa orang berpikir bahwa kita harus mencoba menangani semua jenis error runtime, termasuk. dan situasi OOM. Yang lain percaya bahwa masih sedikit yang dapat dilakukan dengan OOM, dan lebih baik membiarkan aplikasi tersebut mogok. Di sisi kelompok kedua, ada juga fakta bahwa logika pemrosesan OOM tambahan sulit untuk diuji. Dan jika kode tersebut tidak diuji, maka hampir pasti tidak berfungsi.
Saya sangat setuju bahwa Anda tidak harus menerapkan logika penanganan kesalahan yang tidak akan Anda uji. Ini hampir pasti tidak akan memperbaiki apa pun, dan mungkin lebih buruk - merusak segalanya.
Pertanyaan tentang apakah mencoba menangani situasi OOM di perpustakaan / aplikasi kontroversial dan kami tidak akan menyentuhnya di sini. Sebagai bagian dari publikasi ini, saya hanya ingin berbagi pengalaman saya tentang bagaimana Anda dapat menguji logika yang diimplementasikan untuk menangani situasi OOM dalam aplikasi yang ditulis dalam C / C ++. Pembicaraan tentang sistem operasi Linux dan macOS. Karena sejumlah alasan, Windows akan dilewati.
pengantar
Kita semua berharap OOM tidak pernah terjadi, tetapi dalam kehidupan nyata hal ini tidak selalu memungkinkan karena alasan berikut:
- RAM selalu terbatas.
- SWAP tidak selalu diaktifkan.
- Aplikasi tidak selalu berperilaku memadai dan terkadang mencoba mengalokasikan memori dalam jumlah besar secara tidak realistis, mengganggu dirinya sendiri dan orang lain.
- Aplikasi 32-bit masih ada.
- overcommit tidak selalu diaktifkan.
- Konsumsi memori dapat dibatasi penggunaan
ulimit, misalnya. -
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 sendiri telah diuji di Ubuntu (sejak 14.04) dan macOS (sejak Sierra (10.12) dan Xcode 8.3). Selama pengujian, Overthrower mencoba menjatuhkan dirinya sendiri, antara lain.
- Jika OOM nyata muncul di sistem, Pengguling akan melakukan segala kemungkinan untuk tidak jatuh sendiri.