Java'da SIGKILL sinyalini incelikle işleme


113

Program bir kill sinyali aldığında temizlemeyi nasıl halledersiniz?

Örneğin, herhangi bir üçüncü taraf uygulamasının (uygulamam) finishoturumu kapatırken komut göndermesini isteyen bağlandığım bir uygulama var . finishUygulamam bir ile yok edildiğinde bu komutu göndermenin en iyi yolu nedir kill -9?

edit 1: kill -9 yakalanamaz. Beni düzelttiğiniz için teşekkür ederim çocuklar.

düzenleme 2: Sanırım bu durum ctrl-c ile aynı olan sadece kill çağırdığında


44
kill -9benim için şu anlama geliyor: "Defol, faul süreci, senden uzaklaş!", bunun üzerine sürecin sona ereceği. Hemen.
ZoogieZork

11
Bildiğim çoğu * nixte, kill -9 hangi dilde yazılmış olursa olsun hiçbir program tarafından durdurulamaz ve incelikle ele alınamaz.
Başkan James K. Polk

2
@Begui: Başkalarının yorum ve cevaplarına ek olarak, eğer Un x işletim sisteminiz anında öldürmez * VE program tarafından kullanılan TÜM KAYNAKLARI YENİDEN KAZANMAZSA -9'du , iyi ... İşletim sistemi bozuldu.
SözdizimiT3rr0r

1
Kill -9 komutu hakkında, manpage daha kesin bir şekilde şunu söylüyor: "9 KILL (yakalanamaz, göz ardı edilemez öldürme)". SIGKILL, uygulama tarafından değil, işletim sistemi tarafından yönetilen bir sinyaldir.
user1338062

4
Sadece killolarak, Ctrl-C ile aynı değildir killCtrl-C SIGINT gönderir oysa SIGTERM gönderecek gönderme için hangi sinyalin belirtmeden.
alesguzik

Yanıtlar:


136

Öyle imkansız bir SIGKILL işlemek için, herhangi bir dilde, herhangi bir program için. Böylelikle, program hatalı veya kötü niyetli olsa bile, bir programı sonlandırmak her zaman mümkündür. Ancak SIGKILL, bir programı sonlandırmanın tek yolu değildir. Diğeri bir SIGTERM kullanmaktır. Programlar bu sinyali kaldırabilir . Program gerektiğini kontrollü fakat hızlı, kapatma yaparak sinyalini işlemek. Bir bilgisayar kapandığında, kapatma işleminin son aşaması kalan her işleme bir SIGTERM gönderir, bu işlemlere birkaç saniye izin verir ve ardından onlara bir SIGKILL gönderir.

Herhangi bir şey için bunu halletmenin yolu diğer daha kill -9bir kayıt olurdu kapatma kanca. ( SIGTERM ) kullanabiliyorsanız kill -15, kapatma kancası çalışacaktır. ( SIGINT ) kill -2 YAPAR incelikle çıkmak için programın neden ve kapatma kancaları çalıştırın.

Yeni bir sanal makine kapatma kancası kaydeder.

Java sanal makinesi iki tür olaya yanıt olarak kapanır:

  • Son artalan süreci olmayan iş parçacığı çıktığında veya çıkış (eşdeğer olarak System.exit) yöntemi çağrıldığında program normal şekilde çıkar veya
  • Sanal makine, ^ C yazılması gibi bir kullanıcı kesintisine veya kullanıcı oturumu kapatma veya sistem kapatma gibi sistem genelinde bir olaya yanıt olarak sonlandırılır.

Ben OSX 10.6.3 üzerinde aşağıdaki test programı denedik ve üzerinde kill -9o did değil beklendiği gibi kapatma kanca çalıştırın. Bir günü kill -15o GELMEZ kapatma her açtığınızda çalıştırın.

public class TestShutdownHook
{
    public static void main(String[] args) throws InterruptedException
    {
        Runtime.getRuntime().addShutdownHook(new Thread()
        {
            @Override
            public void run()
            {
                System.out.println("Shutdown hook ran!");
            }
        });

        while (true)
        {
            Thread.sleep(1000);
        }
    }
}

kill -9Herhangi bir programda a'yı gerçekten incelikle işlemenin bir yolu yoktur .

Nadir durumlarda, sanal makine temiz bir şekilde kapanmadan durabilir, yani çalışmayı durdurabilir. Bu, sanal makine, örneğin Unix'te SIGKILL sinyali veya Microsoft Windows'ta TerminateProcess çağrısıyla harici olarak sonlandırıldığında meydana gelir.

kill -9A'yı işlemenin tek gerçek seçeneği , ana programınızın kaybolması veya bir sarmalayıcı komut dosyası kullanması için başka bir izleyici program izlemektir. Bunu ps, listede programınızı arayan komutu sorgulayan ve kaybolduğunda buna göre hareket eden bir kabuk betiği ile yapabilirsiniz .

#!/usr/bin/env bash

java TestShutdownHook
wait
# notify your other app that you quit
echo "TestShutdownHook quit"

12

Orada vardır bkz - Bazı JVM'lerle kendi sinyallerini işlemek için yollar HotSpot JVM ile ilgili bu madde örneğin.

Sun dahili sun.misc.Signal.handle(Signal, SignalHandler)yöntem çağrısını kullanarak, bir sinyal işleyiciyi de kaydedebilirsiniz, ancak muhtemelen JVM tarafından kullanılan INTveya benzeri sinyaller için geçerli değildir TERM.

Herhangi bir sinyali idare edebilmek için JVM'den çıkıp İşletim Sistemi bölgesine atlamanız gerekir.

Genellikle anormal sonlandırmayı tespit etmek için (örneğin) yaptığım şey, JVM'mi bir Perl betiği içinde başlatmak, ancak betiğin waitpidsistem çağrısını kullanarak JVM'yi beklemesini sağlamaktır .

Daha sonra JVM'den ne zaman çıktığı ve neden çıktığı konusunda bilgilendiriliyorum ve gerekli önlemi alabiliyorum.


3
Eğer Not olabilir yakalamak INTve TERMsahip sun.misc.Signalama işleyemez QUITayıklama için JVM rezervleri bunu, ne de çünkü KILLişletim sistemi derhal JVM sona erer çünkü. Herhangi birini ele almaya çalışmak bir IllegalArgumentException.
dimo414

12

Ben bekleneceği JVM incelikle kesmeler ( thread.interrupt()) en az sinyalleri için uygulama tarafından oluşturulan tüm çalışan iş parçacığı, SIGINT (kill -2)ve SIGTERM (kill -15).

Bu şekilde, sinyal onlara iletilecek ve standart yollarla zarif bir şekilde iş parçacığı iptaline ve kaynak sonlandırmasına izin verecektir .

Ama bu durum böyle değil benim JVM uygulanmasında en az (: Java(TM) SE Runtime Environment (build 1.8.0_25-b17), Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode).

Diğer kullanıcıların yorumladığı gibi, kapatma kancalarının kullanılması zorunlu görünüyor.

Peki bununla nasıl başa çıkacağım?

Öncelikle, bunu tüm programlarda umursamıyorum, sadece kullanıcı iptallerini ve beklenmedik sonları takip etmek istediğim programlarda. Örneğin, java programınızın başkaları tarafından yönetilen bir süreç olduğunu hayal edin. Nazikçe ( SIGTERMyönetici işleminden) sonlandırılmış mı yoksa bir kapanma mı (işi başlangıçta otomatik olarak yeniden başlatmak için) ayırt etmek isteyebilirsiniz .

Temel olarak, uzun süredir devam eden iş parçacıklarımı her zaman kesintiye uğramış durumdan periyodik olarak haberdar InterruptedExceptionediyorum ve kesildiyse bir atıyorum . Bu, geliştirici tarafından kontrol edilen şekilde yürütmenin tamamlanmasını sağlar (ayrıca standart engelleme işlemleriyle aynı sonucu üretir). Ardından, iplik istifinin en üst seviyesinde InterruptedExceptionyakalanır ve uygun temizlik gerçekleştirilir. Bu iş parçacıkları, bir kesinti talebine nasıl yanıt verileceğini bilecek şekilde kodlanmıştır. Yüksek uyum tasarımı.

Bu nedenle, bu durumlarda, JVM'nin varsayılan olarak yapması gerektiğini düşündüğüm şeyi yapan bir kapatma kancası ekliyorum: uygulamam tarafından oluşturulan ve hala çalışan tüm arka plan programı olmayan iş parçacıklarını kes:

Runtime.getRuntime().addShutdownHook(new Thread() {
    @Override
    public void run() {
        System.out.println("Interrupting threads");
        Set<Thread> runningThreads = Thread.getAllStackTraces().keySet();
        for (Thread th : runningThreads) {
            if (th != Thread.currentThread() 
                && !th.isDaemon() 
                && th.getClass().getName().startsWith("org.brutusin")) {
                System.out.println("Interrupting '" + th.getClass() + "' termination");
                th.interrupt();
            }
        }
        for (Thread th : runningThreads) {
            try {
                if (th != Thread.currentThread() 
                && !th.isDaemon() 
                && th.isInterrupted()) {
                    System.out.println("Waiting '" + th.getName() + "' termination");
                    th.join();
                }
            } catch (InterruptedException ex) {
                System.out.println("Shutdown interrupted");
            }
        }
        System.out.println("Shutdown finished");
    }
});

Github'da test uygulamasını tamamlayın: https://github.com/idelvall/kill-test


6

Kullanabilirsiniz Runtime.getRuntime().addShutdownHook(...), ancak her durumda aranacağına dair garanti verilemez .


12
Ama öldürme durumunda -9 neredeyse kesinlikle çalışmayacaktır.
Başkan James K. Polk

1

Öldürme -9'a tepki vermenin bir yolu vardır: bu, öldürülen süreci izleyen ve gerekirse ardından temizleyen ayrı bir sürece sahip olmaktır. Bu muhtemelen IPC'yi içerecektir ve oldukça fazla iş olacaktır ve her iki işlemi aynı anda öldürerek yine de geçersiz kılabilirsiniz. Çoğu durumda zahmete değmeyeceğini varsayıyorum.

-9 ile bir süreci kim öldürürse, teorik olarak ne yaptığını bilmeli ve işleri tutarsız bir durumda bırakabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.