3

My application is composed of 2 parts -

Some GUI logics in Java. Native code (mainly Delphi) - the GUI implementation itself.

Java uses the native code for trivial operations such as opening windows and responding to user-input events - the implementation is done via JNI.

I'm interested in dividing both sides to different processes - What would be the best way to implement IPC between them without hanging the gui? I'm leaning towards TCP sockets or shared memory, but before I dive into this I'd love to hear some input. Performance and a simple implementation are my main concerns.

Thanks in advance.

  • 1
    Sockets can work well for this in my limited experience. If your GUI is a Swing GUI, you'll need to take care that the inter-process communication be done on a background thread. – Hovercraft Full Of Eels Jun 19 '11 at 21:45
  • I can't see why you'd want to do this. Multiple processes sounds more complex to me. – David Heffernan Jun 19 '11 at 21:57
  • Delphi can't compile on 64 bit OS. Plus the native code has a tendency to crash in extreme cases. – CuriousGeorge Jun 19 '11 at 22:00
  • @curious It will crash just the same in a different process. 64 bit compiler coming very soon now. FreePascal very good and does 64 bit. And what's wrong with running 32 bit code on 64 bit OS? – David Heffernan Jun 19 '11 at 22:13
  • A 32 bit process is limited to 4GB (and even less than that), and my application easily crashes because of OutOfMemory exceptions. Even when the 64 bit compiler comes out it'll be fresh and new, and thus bug-prone. When only the native side crashes, the other process can identify that and quit gracefuly, or recover. Trust me when I say I have good reasons to do that. – CuriousGeorge Jun 19 '11 at 22:18
  • @curious just wait until you try debugging your IPC version! Also, how is IPC going to turn the Delphi process into a 64 bit process? – David Heffernan Jun 19 '11 at 22:25
  • It's not. I don't mind the Delphi process being 32 bit, as it is a fairly thin process.. The Java process however, requires more than 2-3GB so it should fit. Currently the Delphi code is loaded as a dll, so debugging it already a pain! Actually, when I think about it, starting the Delphi process in debug mode should be fairly easier now. Besides, the two processes should be blocking each other whenever one process calls the other one, so that might ease things up (but it also worries me performance-wise, because of context switches and costy "sleeps"). – CuriousGeorge Jun 19 '11 at 22:35

3 Answers3

3

If your problem is about memory consumption

If you're running short of RAM (as suggested by your comments - but you should have better written this in your main question: the more details you give, the better answers you get).

Why are you mixing Java and Delphi? Java is probably not a good candidate do handle more than 1 GB of memory, due to its higher memory consumption for common tasks, and its internal GC. Even if you run the JVM in 64 bit, you'll face new scaling problems: you should have to write very specific code to handle huge memory with Java.

To be fair, the problems doesn't come from Delphi, but from the Java memory consumption. Therefore, IMHO you should better code your data layer in native code. Java is potentially increasing your problems.

You could either:

  • Use the Free Pascal Compiler to compile a 64 bit library from Delphi code, then call it from you main 32 bit Delphi application or from Java using JNI using a Memory Mapped file as bridge.
  • Change the way you access the data. You'll probably won't need to have all those GigaBytes of data at once. You could lay it on disk, then access to it via indexes, which will remain in RAM. If you use Delphi, you should either use your own file handling (you may use something like our BigTable library for storage and indexed access), or use a database (even SQlite3 is able to handle GB of data since its limit is about 140 terabytes, with the power of SQL for retrieving only the data).
  • If you really need to stay in Java, you could probably use some DB instead of plain in-memory structures. You can use SQLite from Java, or a pure Java DB. I suspect it will reduce your memory consumption.

The main approach is: only keep in memory what is needed, and work with Map/Reduce algorithms or some kind of indexes.

If your problem is mixing GUI between Java and Delphi

From my experiment, this could be difficult, because JNI tends to use its own threads, and the VCL expect all its process to be run in the main thread.

So you could either:

  1. Create some Delphi methods, running the VCL Synchronize method when called from the JNI to update the screen.
  2. Rely on Windows GDI messages communication, i.e. create your own WM_USER* handler in the Delphi code, then refresh the screen content from you Java code just by sending some low-level PostMessage or SendMessage API. By design, this will be thread-safe.
  3. Use a stateless approach: I like it very much. Just like in HTTP, you User Interface will act as a Client, and will ask periodically the Data layer (acting as a Server) for refreshed data. All this process will remain in the main thread, and could be easily made via a Timer. With a timer, a 500 ms period for each refresh is enough, and your main application will remain reactive.

In all cases...

For IPC, Memory Mapped files are faster than sockets, but GDI messages are ideal when it deals with some small amount of data. Sockets are good candidates, and will be fast also on a local machine: the small overhead about Memory Mapped files won't be noticeable if the data amount transmitted is only a few KB (up to 1 MB e.g.); and if you need to create a light Client version of your application, it will still work.

Community
  • 1
  • 1
Arnaud Bouchez
  • 42,305
  • 3
  • 71
  • 159
  • Thank you for the detailed reply. I omitted most of those details since they are irrelevant - the system is already up and breathing for some time now. There's a major amount of code in Java, so rewriting it in native code is out of the question. As for implementing a DB - we are already using one. The problem is that sometimes the application actually needs that huge amount of data at hand, and the data manipulation is at a preety fast rate, so adding IO in the middle may slow down the app. – CuriousGeorge Jun 20 '11 at 17:59
  • We are, however, looking into some other solution for that matter (implementing IPC is just another direction we're willing to check). This is a very interesting direction nonetheless, thank you for bringing it to my attention. As for the other solutions you suggested under "mixing GUI between Java and Delphi", we don't have any problem in that area (the JNI communication layer is working just great). Lastly, as I mentioned in other posts, I'm not sure about the FPC being mature enough, but I'm willing to look into that (I understand it won't compile Delphi 2010 code). – CuriousGeorge Jun 20 '11 at 18:18
  • @George FPC is a mature compiler, and outperforms Delphi compiler e.g. for Floating-Point operations (it's able to use SSE opcodes), and for cross-platform / multi-OS support. Of course, it won't compile with Unicode strings, or will have the enhanced RTTI introduced with Delphi 2010. Generics and attributes are available, but not implemented in the same way as Delphi's compiler. And, of course, you don't have the VCL for building the UI. So it's not a clone of Delphi. It's another port of modern object pascal, very suitable for building a computation intensive library. – Arnaud Bouchez Jun 21 '11 at 05:48
  • Unfortunately the project heavily relies on both Unicode strings and VCL, since it's the GUI layer itself. Also - we have some other code that may be problematic to convert to 64 bit so this option seems less reasonable right now. – CuriousGeorge Jun 21 '11 at 18:41
1

The question to your answer depends on your requirements (assuming that you have a good reason to divide the application this way):

If you need to do "trivial" tasks, i.e. not requring much data transfer, then it is probably better to use sockets. You need to create a protocol nevertheless, e.g. respect byte orders. Please also note, that transmitting data will slow down your gui responses.

If you need to transfer larger amounts of data, using shared memory may be more performant. Please note that here you need to do the bookkeeping yourself, that is done by the tcp implementation (e.g. a transmit / receive buffer). Using this The problem of requiring a protocol becomes even worse.

martin
  • 21
  • 1
  • Most of the native calls involve only primitives, except for some special cases that involve objects. How slow should I expect my gui response to become? If it is in terms of microseconds than I guess it won't be noticeable..? – CuriousGeorge Jun 19 '11 at 22:23
  • If your java application is idle, don't expect too much overhead for transfering a few bytes. (i.e. it should be fine) – martin Jun 19 '11 at 22:42
  • "slow down your gui responses" not true at all, there are min. three ways how to move any of proceses to the BackGround Task, please remove this words – mKorbel Jun 19 '11 at 22:59
  • Realistically a user will not notice delays under 100 milliseconds, and unless the application is used for customised data entry, then a delay of up to a second will hardly be noticed. For web-sites most users have become used to delays in the order of seconds or more! Forget about performance - it will just not be an issue. – Misha Jun 20 '11 at 00:01
0

If you want a simple implementation then don't divide the application up into two processes. Performance-wise this is not an issue, but you are adding an order of complexity above what is required in a single application. You would need to have an extremely good reason for dividing the application into multiple proceses to overcome the time and effort that it will cost for you to deliver the same functionality with this architecure.

Misha
  • 1,816
  • 1
  • 13
  • 16