abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    dnes 13:33 | Komunita

    Je druhé úterý v říjnu a tedy všem čtenářkám AbcLinuxu vše nejlepší k dnešnímu Dni Ady Lovelace (Ada Lovelace Day), tj. oslavy žen zabývajících se přírodními vědami, technologiemi, inženýrstvím a matematikou (STEM).

    Ladislav Hagara | Komentářů: 0
    dnes 01:00 | Nová verze

    Byla vydána nová verze 2.47.0 distribuovaného systému správy verzí Git. Přispělo 83 vývojářů, z toho 28 nových. Přehled novinek v příspěvku na blogu GitHubu a v poznámkách k vydání.

    Ladislav Hagara | Komentářů: 0
    dnes 00:11 | Nová verze Ladislav Hagara | Komentářů: 0
    včera 19:55 | Nová verze

    Programovací jazyk Python byl vydán v nové major verzi 3.13.0. Podrobný přehled novinek v changelogu.

    Ladislav Hagara | Komentářů: 0
    včera 17:11 | Zajímavý článek Ladislav Hagara | Komentářů: 4
    včera 15:22 | Pozvánky

    Konference LinuxDays 2024 proběhne již tento víkend 12. a 13. října v Praze. Na programu je spousta zajímavých přednášek a workshopů, zástup zajímavých osobností a stánky řady projektů: Fedora, openSUSE, vpsFree.cz, Mozilla, brmlab, OpenAlt a mnoho dalších. Vstup zdarma.

    Ladislav Hagara | Komentářů: 1
    včera 12:11 | IT novinky Ladislav Hagara | Komentářů: 0
    6.10. 18:55 | Nová verze

    OpenRazer byl vydán ve verzi 3.9.0. Jedná se o svobodný software, ovladač a démon, umožňující nastavovat klávesnice, notebooky, myši, podložky pod myš, keypady, sluchátka a další zařízení od společnosti Razer na GNU/Linuxu.

    Ladislav Hagara | Komentářů: 0
    6.10. 01:55 | Nová verze

    Byla vydána verze 3.6 multiplatformního integrovaného vývojového prostředí (IDE) pro rychlý vývoj aplikaci (RAD) ve Free Pascalu Lazarus (Wikipedie). Přehled novinek v poznámkách k vydání. Využíván je Free Pascal Compiler (FPC) 3.2.2.

    Ladislav Hagara | Komentářů: 40
    6.10. 00:33 | Komunita

    Na čem aktuálně pracují vývojáři GNOME a KDE? Pravidelný přehled novinek v Týden v GNOME a Týden v KDE.

    Ladislav Hagara | Komentářů: 1
    Rozcestník

    Java Native Interface: propojujeme Javu a C/C++ – 1

    21. 10. 2010 | Luboš Doležel | Programování | 7116×

    Java Native Interface (JNI) je rozhraní pro jazyk C, které umožňuje v Java aplikacích využívat nativní knihovny, a naopak také využívat Javu v nativních aplikacích. Tento seriál vám JNI představí a naučí vás jej používat.
    Java Duke

    Obsah

    JNI – co a proč to je

    link

    Ačkoliv je výbava Java Class Library s každou verzí lepší a lepší, ne vždy je dostatečná pro některé low level úlohy, nebo Java zkrátka neposkytuje (JITu navzdory) výkon, který nám může poskytnout pečlivě zoptimalizovaný kód. Dalším důvodem, proč JNI vzniklo, je napojení na knihovny systému a další platformně specifické věci – příkladem budiž SWT, které se v závislosti na aktuálním systému skrze JNI knihovny napojuje na nativní knihovny pro tvorbu GUI.

    Nevýhodou použití JNI v této situaci je ztráta nezávislosti na hardwarové a softwarové platformě, neboť nativní knihovna musí být zkompilována například pro x86 a amd64 zvlášť a jednu knihovnu nemůžeme použít pro Windows a Linux zároveň. Je tedy důležité k JNI přistupovat s rozmyslem.

    Opačný přístup je nasazování Javy v nativních aplikacích, což bude tématem pozdějších článků z tohoto seriálu. V této situaci nepředstavuje použití Javy žádné speciální komplikace, snad jen to, že samozřejmě musíme zajistit, aby na cílovém systému bylo k dispozici funkční a dostatečně aktuální JRE. Možná se ptáte, nač kazit rychlou nativní aplikaci tou „pomalou a rozežranou“ Javou. Java díky své mocnosti a dostupnosti nepřeberného množství knihoven představuje jednoho z kandidátů na tvorbu rozšíření do nativních aplikací. Snad nejznámější aplikací, kde se Java takto používá, je OpenOffice.org; nutno však podotknout, že za pomalostí tohoto kancelářského balíku není Java. Ba naopak, Java se dle mých zkušeností dokáže chovat přinejmenším stejně paměťově skromně jako jiné jazyky typické pro tento účel (Python a spol.).

    Oproti (mnohdy interpretovaným) skriptovacím jazykům, které typicky obsazují místo jazyků pro rozšíření, Java nabízí vlastnosti silně typovaného jazyka, vyšší výkon díky JIT kompilaci a kromě toho garanci „stabilního zázemí“, kdy celá Java Class Library je zaručenou součástí každé instalace JRE. Uživatel si tak nemusí instalovat spousty wrapperů pro zvolený skriptovací jazyk a programátor nemusí řešit, co dělat, když knihovna nebude nainstalovaná, ačkoliv uznávám, že nenávist k desítkám instalovaných py a -ruby wrapperů je spíše mým osobním pohledem a záští.

    Na co si dávat pozor

    link

    JNI bohužel patří mezi API, která jsou Sunem a nyní Oraclem dosti zanedbávána. Na rozdíl od samotné Javy je dokumentace JNI dosti strohá (dva HTML soubory) a některé věci je nutné zjišťovat metodou pokus-omyl. Za poslední roky tato dokumentace dostala pouze "facelift", ale že nefunguje ani skákání na jednotlivé odstavce v dokumentu, to už nikoho nezajímalo. Bohužel i z hlediska používání rozhraní je třeba vždy myslet na to, že JNI si nikdy neporadí se špatným argumentem. Null pointer znamená pád, šáhnutí za konec pole znamená pád (žádné ArrayOutOfBoundsException) a překlep v názvu nativní metody při registraci znamená také pád, a to dokonce ještě s pěkným ohňostrojem.

    Ne nadarmo se při psaní nativních knihoven doporučuje v knihovnách provádět holé minimum práce a zbytek napsat v Javě. Tímto pravidlem se řídí i samotný Sun/Oracle. Kromě nižšího rizika chyb je tu i zjevný důvod, že údržba takového kódu je ve výsledku snazší. Je to dobré pro přehlednost, neboť veškerá logika je pak na jediném místě a ne rozdělena mezi Java a C kód.

    Začínáme: obohacujeme Javu o nativní kód

    link

    Nejprve se podíváme na to, jak proces načítání a používání nativních knihoven funguje na straně Javy. Nativní metody se v Javě vyznačují klíčovým slovem native, taková jednoduchá třída tedy může vypadat následovně:

    package test;
    
    public class TestNative {
    	public static void javaMethod() { /* ... */ }
    	public static native int nativeMethod(int myNumber);
    }
    
    

    Pokud zavoláme metodu nativeMethod() v této situaci (kdy jsme nedodali odpovídající nativní kód), volání selže s výjimkou java.lang.UnsatisfiedLinkError: test.test.TestNative.nativeMethod(I)I. Dalším krokem je nechat si vygenerovat hlavičkový soubor s deklaracemi pro jazyk C – k romu slouží konzolový nástroj javah, jenž je součástí JDK. Javah pracuje nad zkompilovanými třídami, volitelně mu tedy předáváme classpath s umístěním těchto tříd.

    $ javah -classpath ./build/classes test.TestNative
    $ ls *.h
    test_TestNative.h
    

    V aktuálním adresáři nám vznikne hlavičkový soubor pojmenovaný podle balíčku a třídy. Soubor je přizpůsoben pro použití v C i C++.

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class test_TestNative */
    
    #ifndef _Included_test_TestNative
    #define _Included_test_TestNative
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     test_TestNative
     * Method:    nativeMethod
     * Signature: (I)I
     */
    JNIEXPORT jint JNICALL Java_test_TestNative_nativeMethod
      (JNIEnv *, jclass, jint);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    

    Naše oči hned zabrousí k funkci void Java_test_TestNative_nativeMethod(JNIEnv *, jclass, jint), kterou máme naimplementovat. Uděláme si takový malý Hello world. Soubor test_TestNative.cpp:

    #include "test_TestNative.h"
    #include <iostream>
    
    jint Java_test_TestNative_nativeMethod(JNIEnv* env, jclass myClass, jint myNumber)
    {
            std::cout << "Hello world!\n";
            std::cout << "Argument value: " << myNumber << std::endl;
            return -myNumber;
    }
    

    Nyní si z tohoto zdrojáku zkompilujeme sdílenou knihovnu. Samozřejmě by bylo lepší použít nějaký Makefile nebo rovnou použít autotools a podobné, ale pro jednoduchost ukážu příkaz přímo pro GCC s include cestami dle mého systému:

    $ g++ -fPIC -shared \
    >	-I /usr/lib/jvm/java-6-sun-1.6.0.21/include \
    >	-I /usr/lib/jvm/java-6-sun-1.6.0.21/include/linux \
    >	-o /tmp/libtestnative.so test_TestNative.cpp
    

    Teď naší javovskou třídu obohatíme o metodu main a necháme Javu načíst naší nativní knihovnu:

    public static void main(String[] args) {
    	System.loadLibrary("testnative");
    	int r = nativeMethod(123);
    	System.out.println("The native method has returned " + r);
    }
    

    Javovské System.loadLibrary respektuje zvyklosti z různých operačních systémů, na Linuxu je to prefix lib před názvem knihovny. System.loadLibrary("testnative") tedy na Linuxu zkusí načíst libtestnative.so. Poslední věc je Javě říci, kde má knihovnu hledat, a to nastavením java.library.path (něco na způsob známého LD_LIBRARY_PATH). Nyní tedy nazdar světe!

    $ java -Djava.library.path=/tmp -cp build/classes test.TestNative
    Hello world!
    Argument value: 123
    The native method has returned -123
    

    Z ukázky tedy vidíme, že předávání a vracení primitivních typů je velmi jednoduché. Kromě argumentů, které předáváme z Javy, dostává naše nativní funkce ještě dva argumenty. Ten první – JNIEnv* env – představuje bránu do javovského světa a je objektem, který budeme brzy velmi aktivně využívat. Jinak než pomocí JNIEnv nelze funkce JNI volat, snad jen s výjimkou funkce pro vytvoření JVM z nativní aplikace. Druhý argument – jclass myClass – dostávají pouze statické metody a jde o céčkovou reprezentaci instance java.lang.Class, jež bychom v javovském kódu našli jako test.TestNative.class.

    V příštím díle se přesuneme od primitivních typů k objektům a zkusíme si vytvořit nějaký ten String.

           

    Hodnocení: 100 %

            špatnédobré        

    Nástroje: Tisk bez diskuse

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    Komentáře

    Vložit další komentář

    21.10.2010 06:49 Martin Beránek | skóre: 33 | blog: mousehouse | Brno
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Díky. Pěkné. Zatím jsem JNI nikdy k ničemu nepotřeboval, ale to se může změnit. Přestože toto je na Linux zaměřený server, nebyl by nějaký příklad cross-compilace i pro windows?
    never use rm after eight
    Luboš Doležel (Doli) avatar 21.10.2010 12:20 Luboš Doležel (Doli) | skóre: 98 | blog: Doliho blog | Kladensko
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    To už je hodně dlouho, co jsem dělal crosscompilaci. Na Gentoo šlo crosscompilátor hezky zkompilovat a pak používat, na Debianu nevím, ale nějaký mingw tu je.
    21.10.2010 07:18 Sid
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Myslim, ze pre bezne veci je urcite lepsie pouzit JNA ktore zapuzdruje JNI.
    21.10.2010 09:55 vyzivus
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Vdaka za clanok, ale tiez odporucam JNA - nie je nutne robit ziadne zmeny do C kniznice (pridavat JNIEXPORT apod), krasne podporuje struct, pstruct a dalsie veci. Viac na https://jna.dev.java.net/
    Luboš Doležel (Doli) avatar 21.10.2010 11:16 Luboš Doležel (Doli) | skóre: 98 | blog: Doliho blog | Kladensko
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Na JNA dojde taky. JNI ukazuju hlavně kvůli použitelnosti v obou směrech (nativní kód z Javy i Java z nativního kódu).
    22.10.2010 11:07 pepa_u
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Chapu to spravne, ze JNA umoznuje akorat volani native funkci, nicmene, potrebuji-li pouzit objekty z C++, pak se JNI a vlastnimu wrapperu nevyhnu?
    21.10.2010 14:00 Honza
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    To jsem zvědavý, co z toho seriálu vyleze. dělám v práci na Androidu, hodně i s NDK, takže JNI se dost zabývám. Taky už jsem se párkrát dost nachytal, třeba s nemazáním lokálních referencí v cyklu (padačka) nebo různé radosti s vlákny a neplatností JNIEnv *.
    Luboš Doležel (Doli) avatar 21.10.2010 14:13 Luboš Doležel (Doli) | skóre: 98 | blog: Doliho blog | Kladensko
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Reference jsou někdy pěkná pakárna, proto jsem si na vše, co tu budu popisovat, nakonec napsal wrapper. Dokud jsem si vše řádně neowrapoval, byl někdy pěkný boj najít důvod proč to padá nebo proč mám v rukou najednou úplně jiný objekt.
    třeba s nemazáním lokálních referencí v cyklu (padačka)
    To padalo kvůli překročení maximálního počtu referencí ve scope? Jinak si teď nedovedu představit, proč by to padalo.
    22.10.2010 12:10 Honza
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Jojo, maximílní počet referencí. Na rozumně krátkých testovacích datech vše perfektně fungovalo. Ale pak si zákazník synchronizoval kontakty s facebookem a to už while cyklus přes kontakty s nemazáním lokální reference (přece ji to pak smaže samo, až se vrátim do javy, že...) neustál :-)
    22.10.2010 12:12 Honza
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Další moje oblíbená chybka je nevytvoření globální reference. Do se taky príma ladí...
    Luboš Doležel (Doli) avatar 22.10.2010 12:53 Luboš Doležel (Doli) | skóre: 98 | blog: Doliho blog | Kladensko
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    To mi povídej...

    Mrkni na můj wrapper. Ten všechny lokální reference rovnou ruší a místo nich si zakládá globální, o jejichž zrušení se pak stará destruktor třídy.
    23.10.2010 17:41 arny
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Ja s JNI nemam velmi dobre skusenosti. Problem je hlavne v nemanageovanej a manageovanej pamati. Kazdy pad ci uz nativnej kniznice alebo JNI rozhrania, znamena pad celej aplikacie. Z tohto dovodu je dobre pouzivat zasadu, ze co najviac sa vyhybat nativnym knizniciam a ked ich uz musim pouzit tak izolovat izolovat a zasa izolovat a to najlepsie do separatneho procesu. Pri desktopovych aplikaciach to este nemusi byt velky problem, ale ked vam padne cely server, tak to potom zacina zabava. V podstate JNI dedi chyby po nativnej kniznici a pokial si ju este nevytvarate sami ale pouzivate nejaky tretostrannu kniznicu, tak mate o zabavu postarane.
    24.10.2010 14:57 kralyk z abclinuxu | skóre: 29 | blog:
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Z tohto dovodu je dobre pouzivat zasadu, ze co najviac sa vyhybat nativnym knizniciam a ked ich uz musim pouzit tak izolovat izolovat a zasa izolovat a to najlepsie do separatneho procesu.
    Což má ale dopad na výkon, v některých případech může být i dost vysoký...
    24.10.2010 15:16 arny
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Ano ma ale poznas ten vtip o pentiu, ked sa ho AMD pytalo kolko je 2+2 a ono odpovedalo, ze 5. AMD na to ze to nieje spravne ale pentium povedalo, ze je to rychle. Proste ked sa mas rozhodnut medzi rychlostou a stabilitou ja osobne volim stabilitu.
    27.10.2010 02:59 kralyk z abclinuxu | skóre: 29 | blog:
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Nějak mi není jasný, jak ti nenativita nějaké knihovny zaručuje její stabilitu?

    K tomu vtipu: Nativní aplikace dokážou podávat výsledek nejen rychle, ale i správný ;-)
    2.11.2010 17:36 arny
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Nezarucuje, ale podstatne ju zvysuje.
    Luboš Doležel (Doli) avatar 24.10.2010 15:05 Luboš Doležel (Doli) | skóre: 98 | blog: Doliho blog | Kladensko
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Pri desktopovych aplikaciach to este nemusi byt velky problem, ale ked vam padne cely server, tak to potom zacina zabava.
    Máš pravdu, ale je to trochu přehnané - takhle to mají všechny nativní aplikace a myslím si, že obecně jsou tyto na serverech v průměru v převaze :-)
    24.10.2010 15:19 arny
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Vobec to nieje prehnane. Ked ti zrazu z nicoho nic padne cely web server a ty budes hladat kade tade po logoch a najdes akurat pad glibc koli dvojitemu uvolneniu pamate a vobec nebudes vediet, ktora z nativnych kniznic to urobila a preco, tak potom ti nebude do smiechu. Hlavne ked sa jedna o produkcny server. A ci su nativne aplikacie na serveroch v prevahe o tom by sa dalo polemizovat. Podla mna drtiva vacsina web aplikacii su vytvarane v php,java,.net a python a to vacsinou bez pouzitia nativnych kniznic.
    Luboš Doležel (Doli) avatar 24.10.2010 15:21 Luboš Doležel (Doli) | skóre: 98 | blog: Doliho blog | Kladensko
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Podla mna drtiva vacsina web aplikacii su vytvarane v php,java,.net a python a to vacsinou bez pouzitia nativnych kniznic.
    Nevěděl jsem, že se bavíme o webových aplikacích...
    26.10.2010 20:57 XMen
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    sorry, nespomenul som to ale ano, hovorim o webovych aplikaciach. Kazdopadne problem vidim aj na desktopovych aj ked tam pad aplikacie neznamena pad aplikacie pre vsetkych jej uzivatelov. Aby som sa spravne vyjadril niesom proti nativnym knizniciam. Niekedy je to proste jedina moznost ci uz z dovodu pridania novej funkcionality alebo vykonu, ale treba si na ne davat podstatne vacsi pozor.
    27.10.2010 02:57 kralyk z abclinuxu | skóre: 29 | blog:
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Zkus si vzít ldd a vypsat si, na jakých všech nativních knihovnách (včetně zanořených) závisí běžný virtuální stroj nebo interpretr.
    I. e. je potřeba si dávat na nativní a nenativní implementace zhruba stejný pozor...
    Bilbo avatar 28.10.2010 03:58 Bilbo | skóre: 29
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Pokud je něco blbě naprogramovaný, tak je jedno jestli v Javě, nebo ne. Memory leaky se dají dělat i v Javě (stačí mít někde zapomenutou referenci na něco někde v nějakém seznamu - request odkazuje nas dokument, dokument odkazuje na session, session odkazuje na cookie a request ... , když se to dostatečně "dobře" zamotá, tak GC nemá šanci v tom chuchvalci referencí nic sklidit .... a o sklizeň se pak postará až OOM killer, který to ale vezme velmi důkladně), pokud "hlavní" vlákno aplikace/serveru postihne nějaký ten deadlock (i to se v Javě stává), tak sice technicky aplikace běží, ale prakticky je zralá akorát tak na odstřel.

    Jeva je trošku odolnější vůči pár typům chyb díky trochu robustnějšímu managementu paměti a vyjímkám, ale všelék na nepadavou a vždy funkční aplikaci to není.
    Big brother is not watching you anymore. Big Brother is telling you how to live...
    Algi avatar 10.11.2010 16:51 Algi | skóre: 1 | blog: Sinner
    Rozbalit Rozbalit vše Re: Java Native Interface: propojujeme Javu a C/C++ – 1
    Já bych dokonce řekl, že memory leaky v Javě nejsou ani žádnou vzácností. Používat alespoň VisualVM se rozhodně vyplatí, dokáže to i odhalit díky leakům některé chyby v implementaci, které by si člověk jinak neuvědomil. A je úplně jedno, jestli to je webová či desktopová aplikace...
    I'm a firestarter, twisted firestarter...

    Založit nové vláknoNahoru

    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.