2009-07-14 8 views
18

Ich arbeite an einer Java-Anwendung, die mit einer C-Anwendung kommunizieren muss. Die C-Anwendung verwendet gemeinsamen Speicher und mmap, um zu kommunizieren, und ich brauche die Java-Anwendung, um auf denselben Speicher zugreifen zu können.Wie ist der beste Weg, um in Java auf den Speicher zuzugreifen, ähnlich wie bei mmap?

Mein erster Versuch bestand darin, JNI-Aufrufe zum Abrufen von Daten aus dem gemeinsamen Speicher zu verwenden, aber der Overhead jedes JNI-Aufrufs führte zu Leistungseinbußen. Daher möchte ich einen Zugriff auf diesen Speicher in Java erhalten und die Datenabfrage durchführen die Java-Seite.

Die Idee, die ich habe ist, dass ich folgendes tun bräuchten:

  1. Verwenden Sie eine JNI Aufruf die Position des gemeinsam genutzten Speicherplatz ich
  2. ein neues Filechannel erstellen anhängen müssen zu erhalten (
  3. )
  4. verwenden, die einen Filechannel MappedByteBuffer mit Karte()

Ist dies der beste Weg zu schaffen, dies zu tun? Außerdem bin ich mir nicht sicher, wie ich den FileChannel tatsächlich erstellen soll, um auf den richtigen Speicherort zu zeigen.

+0

imho können Sie nicht, aber ich liebe es, korrigiert zu werden – dfa

Antwort

11

Unter Verwendung von ByteBuffer.allocateDirect untersuchen. Offensichtlich können diese Puffer über den JNI-Layer an nativen Code übergeben werden, der direkt auf den Speicher zugreifen kann.

Siehe this page (zitiert unten) für Hinweise.

Nun kann JNI nicht nur die Adresse des nativen Speicherplatzes in einem mit ByteBuffer erstellten Puffer erkennen.allocateDirect() auf der Java-Seite, aber es kann seinen eigenen Speicher (z. B. mit malloc) zuweisen und dann an die JVM zurückrufen, um diesen Speicherbereich in ein neues ByteBuffer-Objekt einzubinden (die JNI-Methode dafür ist NewDirectByteBuffer)()).

+1

Das wird so nah am Metall sein wie in Java. Unglücklicherweise muss der ByteBuffer immer noch Informationen über die VM-Grenze ziehen. Es mag lehrreich sein, sich anzuschauen, wie das JDK den Deflator implementiert - http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/Deflater.html –

+2

Ich habe ByteBuffers benutzt und sie haben fantastisch gearbeitet. Im JNI-Code habe ich einen ByteBuffer erstellt und an den Java-Code zurückgegeben, der dann direkt auf diesen Speicher zugreifen kann. Am Ende konnten meine Java-Anwendungen den Speicher lesen und darauf schreiben. Schriftsätze wären sofort für alle C/C++ - Anwendungen sichtbar, die denselben Speicher verwenden. – Brian

-2

Wenn Sie die Daten in einer Datei in C speichern und dann auf die Datei von Java zugreifen könnten, wäre das am besten. AFAIK können Sie nicht auf den Speicher verweisen, wie Sie Java verwenden möchten.

+0

Das ist einfach falsch. Direkte Bytepuffer bieten die gewünschte Fähigkeit. –

0

Wenn Sie sowohl die C-und Java-Anwendung besitzen, könnten sie nur über die Konsolenströme kommunizieren - hässlich für Binärdaten, aber möglich. Ich würde den gemeinsamen Speicher für einen mehr Nachrichtenübermittlungsstil austauschen - z. TCP/IP-Socket-Paar.

BTW, welche Art von Daten wird herumgereicht und wie groß ist es?

+0

Ich bin nicht genau sicher, die Größe; könnte ungefähr 800Mb zu über einem Gb sein. Leider habe ich nicht den Luxus, die C-Anwendung zu modifizieren. – Brian

+0

Erstellen Sie eine neue C-Anwendung, die die ursprüngliche C-Anwendung umschließt. Sobald Sie das tun, sollte entweder die Lösung von kd304 oder die Lösung von AlbertoPL möglich sein. – NamshubWriter

+0

Ist es immer notwendig, die gesamten Daten zwischen den Apps zu verschieben? – akarnokd

1

würde ich ein kleines C-Modul schreiben mmaps den gemeinsam genutzten Speicher und verwendet Sockets eine andere Anwendung zu ermöglichen, dass der Speicher zu sehen (zB Java-app)

0

Könnten Sie nicht eine Java-Klasse mit einigen nativen Methoden schreiben, schreiben die native Methodenimplementierung in C, um mit mmap zu tun, was Sie wollen. Kompilieren Sie das anschließend in eine systemeigene Bibliothek, und fügen Sie es mithilfe von LD_LIBRARY_PATH zu Ihrer Laufzeit hinzu. Dies ermöglicht es Ihnen, native C-Aufrufe in Java ohne den JNI-Overhead durchzuführen (glaube ich).

Einige Tutorials hier: link

Zum Beispiel würden Sie eine Java-Klasse schreiben wie:

JMMap.java 

public class JMMap { 
    public native void write(...) 
} 

Dann javah gegen die Klasse-Datei ausführen, wie etwas zu produzieren:

JMMap.h 

JNIEXPORT void JNICALL Java_JMMap_write(JNIEnv *, jobject); 

Implementieren Sie dies in einer .c-Datei. Kompilieren Sie das zu einer Bibliothek. Fügen Sie es dem LD-Pfad hinzu und rufen Sie dann einfach die Java-Funktion auf.

Verwandte Themen