GNU/Linux >> Belajar Linux >  >> Linux

Pemborosan waktu execv() dan fork()

Tidak lagi. Ada sesuatu yang disebut COW (Copy On Write), hanya ketika salah satu dari dua proses (Induk/Anak) mencoba untuk menulis ke data bersama, itu akan disalin.

Di masa lalu:
fork() system call menyalin ruang alamat dari proses pemanggilan (induk) untuk membuat proses baru (anak). Menyalin ruang alamat induk ke anak adalah bagian termahal dari fork() operasi.

Sekarang:
Panggilan ke fork() sering diikuti segera oleh panggilan ke exec() dalam proses anak, yang menggantikan memori anak dengan program baru. Inilah yang biasanya dilakukan oleh shell, misalnya. Dalam hal ini, waktu yang dihabiskan untuk menyalin ruang alamat induk sebagian besar terbuang sia-sia, karena proses anak akan menggunakan sangat sedikit memorinya sebelum memanggil exec() .

Untuk alasan ini, versi Unix yang lebih baru memanfaatkan perangkat keras memori virtual untuk memungkinkan orang tua dan anak berbagi memori yang dipetakan ke ruang alamat masing-masing hingga salah satu proses benar-benar memodifikasinya. Teknik ini dikenal sebagai copy-on-write . Untuk melakukannya, pada fork() kernel akan menyalin pemetaan ruang alamat dari induk ke anak alih-alih konten halaman yang dipetakan, dan pada saat yang sama menandai halaman yang sekarang dibagikan sebagai hanya baca. Ketika salah satu dari dua proses mencoba menulis ke salah satu halaman yang dibagikan ini, proses tersebut mengalami kesalahan halaman. Pada titik ini, kernel Unix menyadari bahwa halaman tersebut benar-benar salinan "virtual" atau "copy-on-write", sehingga membuat salinan halaman yang baru, pribadi, dan dapat ditulis untuk proses kesalahan. Dengan cara ini, konten halaman individu tidak benar-benar disalin sampai benar-benar ditulis. Pengoptimalan ini menghasilkan fork() diikuti dengan exec() pada anak jauh lebih murah:anak mungkin hanya perlu menyalin satu halaman (halaman saat ini dari tumpukannya) sebelum memanggil exec() .


Apa keuntungan yang dicapai dengan menggunakan kombo ini (bukan solusi lain) yang membuat orang tetap menggunakan ini meskipun kita memiliki pemborosan?

Anda harus membuat proses baru entah bagaimana. Ada sangat sedikit cara untuk program userspace untuk mencapai itu. POSIX dulu memiliki vfork() di samping fork() , dan beberapa sistem mungkin memiliki mekanismenya sendiri, seperti clone() khusus Linux , tetapi sejak 2008, POSIX hanya menetapkan fork() dan posix_spawn() keluarga. fork + exec rute lebih tradisional, dipahami dengan baik, dan memiliki sedikit kekurangan (lihat di bawah). posix_spawn keluarga dirancang sebagai tujuan khusus pengganti penggunaan dalam konteks yang menghadirkan kesulitan untuk fork(); Anda dapat menemukan detailnya di bagian "Dasar Pemikiran" dari spesifikasinya.

Kutipan ini dari halaman manual Linux untuk vfork() mungkin mencerahkan:

Di bawah Linux, fork (2) diimplementasikan menggunakan halaman copy-on-write, jadi satu-satunya penalti yang dikenakan oleh fork (2) adalah waktu dan memori yang diperlukan untuk menduplikasi tabel halaman induk, dan untuk membuat struktur tugas unik untuk anak . Namun, di masa lalu yang buruk, fork (2) akan membutuhkan salinan lengkap dari ruang data penelepon, sering kali tidak perlu, karena biasanya segera setelah itu sebuah exec (3) dilakukan. Jadi, untuk efisiensi yang lebih besar, BSD memperkenalkan vfork () panggilan sistem, yang tidak sepenuhnya menyalin ruang alamat proses induk, tetapi meminjam memori induk dan utas kontrol hingga panggilan ke execve (2) atau keluar terjadi. Proses induk ditangguhkan saat anak menggunakan sumber dayanya. Penggunaan vfork () rumit:misalnya, tidak mengubah data dalam proses induk bergantung pada mengetahui variabel mana yang disimpan dalam register.

(Penekanan ditambahkan)

Dengan demikian, kekhawatiran Anda tentang pemborosan tidak beralasan untuk sistem modern (tidak terbatas pada Linux), tetapi itu memang merupakan masalah secara historis, dan memang ada mekanisme yang dirancang untuk menghindarinya. Saat ini, sebagian besar mekanisme tersebut sudah usang.


Jawaban lain menyatakan:

Namun, di masa lalu yang buruk, fork(2) akan memerlukan salinan lengkap dari ruang data pemanggil, seringkali tidak perlu, karena biasanya segera setelah itu exec(3) selesai.

Jelas, masa lalu buruk seseorang jauh lebih muda daripada yang diingat orang lain.

Sistem UNIX asli tidak memiliki memori untuk menjalankan banyak proses dan mereka tidak memiliki MMU untuk menyimpan beberapa proses dalam memori fisik yang siap dijalankan pada ruang alamat logis yang sama:mereka menukar proses ke disk yang bukan sedang berjalan.

Panggilan sistem garpu hampir seluruhnya sama dengan menukar proses saat ini ke disk, kecuali untuk nilai kembalian dan untuk tidak mengganti salinan dalam memori yang tersisa dengan menukar dalam proses lain. Karena Anda tetap harus menukar proses induk untuk menjalankan anak, fork+exec tidak menimbulkan biaya tambahan apa pun.

Memang benar bahwa ada periode waktu ketika fork+exec canggung:ketika ada MMU yang menyediakan pemetaan antara ruang alamat logis dan fisik tetapi kesalahan halaman tidak menyimpan informasi yang cukup yang copy-on-write dan sejumlah virtual lainnya -memory/demand-paging skema yang layak.

Situasi ini cukup menyakitkan, tidak hanya untuk UNIX, penanganan kesalahan halaman pada perangkat keras diadaptasi menjadi "dapat diputar ulang" dengan cukup cepat.


Linux
  1. Dapatkan Waktu Pengguna Dan Kernel Dari Proses yang Berjalan?

  2. Perbedaan antara CLOCK_REALTIME dan CLOCK_MONOTONIC?

  3. Perbedaan antara fork(), vfork(), exec() dan clone()

  1. Fork panggilan sistem () dan fungsi execv

  2. Dapatkan waktu saat ini dalam jam dan menit

  3. PHP dan mod_fcgid:ap_pass_brigade gagal dalam fungsi handle_request_ipc

  1. Cara Menemukan dan Membunuh Proses Zombie di Linux

  2. Temukan Waktu Eksekusi Perintah Atau Proses Di Linux

  3. cap waktu, waktu modifikasi, dan waktu pembuatan file