JVM共享内存

4

我有一些关于JAVA的疑问。我有一个任务执行器,每个任务都会创建一个新的线程,每个线程将从jar中执行一个任务。

Runtime.getRuntime().exec(" java -jar myjar");

我在一些帖子中读到,通过这种方式执行每个线程将创建自己的JVM。然后,如果我想使用两个线程执行相同的类或来自同一jar的不同类,它将在两个JVM中创建相同jar的副本。实际上,我想避免在两个JVM中复制相同的jar。相反,我想在多个JVM之间共享相同的jar。
请给出一些关于这种情况的提示。

1
你应该从第一原则开始,阅读有关该主题的基础教程,例如http://docs.oracle.com/javase/tutorial/essential/concurrency/procthread.html。 - Matt
3个回答

0

JVM 不需要自己的一个 JAR 副本,只需要在其类路径中找到它即可。同一个 JAR 可以在多个运行中的 Java 程序的类路径中存在。

当然,每个 JVM 都有自己的内存,在其类路径中的 JAR 中加载的类将加载在每个 JVM 的内存中。两个不同 JVM 加载的类共享同一内存是不可能的。如果您想要共享内存,不要使用几个 Java 进程,而是使用线程。


0

你并不是真的将一个“jar文件复制”到JVM中。你只是从中加载需要的类,而且只有那些需要的类。除非你设法获取了几个MiB大小的大量类文件,并产生了数十个这样的进程,否则这不应该是什么问题。最好让每个JVM进程自己解决自己的问题,保持简单。当运行多个JVM时,后台可能会进行一些优化。不要对实现优化进行猜测。

如果这确实是某种绝对要求,那么你将面临困难。我能想到的唯一解决方案是编写一个自定义类加载器,以某种方式使用共享内存。这很可能涉及使用Java本地接口,迫使你编写特定于平台的代码。也许有一些可用的解决方案,但我不知道有这样的东西。

而且这一切都是基于你首先应该生成其他Java进程的假设。我认为你最好考虑一种方法,让这些其他进程在同一个Java进程中的不同线程中运行。Java并发工具(在java.util.concurrent包中)已经使这些事情变得更加可管理。

HotSpot JVM本身使用类数据共享在系统JAR文件上以减少内存占用和加速多个JVM的引导。也许源代码可以提供一些思路。但我认为,除非你遇到严重的内存问题并且确实需要多个进程,否则这应该是尝试解决任何问题的绝对最后一件事情。你正在尝试优化一个应该远离的东西。

你好 G_H,我能再澄清一些事情吗?“您正在从中加载类,并且仅加载所需的那些类。”上述语句的意思是否是这样的:“当我执行Runtime.getRuntime().exec(" java -jar myjar");时,它将最初将在manifest.mf中提到的主类加载到每个jvm的内存中。如果主类调用其他类,则会将其加载到相应的jvm内存中。” - nantitv
@nantitv 只有在运行时需要时,类才会被加载,除非您使用自定义类加载器更改此行为。现在我不知道默认的JVM类加载器如何读取jar文件,但我想它们只在必要时访问它们。即使它们更早地加载其他数据,那也是有充分理由的。只需依靠JVM完成其工作,不必担心微小的优化。 - G_H

0
(当然,您可以让两个JVM共享一个JAR文件,并且这不会“创建副本”...但我认为这不是您真正想问的问题。)

Sun/Oracle Java有一个名为CDS(在Java 5.0中引入)的功能,允许从“rt.jar”加载的类在多个JVM实例之间共享。编译后的类保存到称为“共享存档”的东西中,然后可以将其内存映射到多个JVM的地址空间中...以加快JVM启动速度。但是,CDS不适用于应用程序类。

显然,IBM的Java 5实现具有类似的功能,称为"Shared Classes", 可以用于应用程序类。


你可能可以通过这种方式节约一些内存,但并不清楚你能够节省多少内存。如果你非常关心内存使用和JVM启动时间,最好是在父JVM中运行子Java应用程序。(当然,缺点是如果任何一个子Java应用程序行为异常,它可能会导致问题,只能通过退出父JVM来解决。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接