我正在尝试提高java应用程序的可伸缩性,该应用程序在单独的线程中处理许多小任务。但它显示出意想不到的糟糕结果。内存分配似乎根本不可扩展。这很奇怪,因为每个线程都在本地分配对象。 Java内存管理器应该能够在线程的本地堆中分配它们而无需全局锁定。 GC线程不显示任何重要活动。 有一个简单的测试:
private static class AllocTest implements Runnable
{
@Override
public void run()
{
for (int i = 0; i < 100000; ++i)
{
char[] s = new char[100];
}
}
}
final int THREADS_COUNT = 4;
LinkedBlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<Runnable>(THREADS_COUNT);
ThreadFactory threadFactory = Executors.defaultThreadFactory();
ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_COUNT, THREADS_COUNT, 1, TimeUnit.HOURS, taskQueue, threadFactory);
pool.prestartAllCoreThreads();
long startTime = System.nanoTime();
for (int i = 0; i < 1000; ++i)
{
pool.getQueue().offer(new AllocTest(), 1, TimeUnit.MINUTES);
}
pool.shutdown();
pool.awaitTermination(1, TimeUnit.HOURS);
long endTime = System.nanoTime();
System.out.print("Elapsed time: ");
System.out.print(TimeUnit.NANOSECONDS.toMillis(endTime - startTime));
将线程数(THREADS_COUNT)从1更改为4,得到的结果几乎相同: THREADS_COUNT时间
使用&#34; -server&#34;运行测试VM标志。 Java版本 - 1.8.0_66。 在平台上试用 - Windows 7 x64(1个处理器,8个内核),SunOS 5.10 x64(2个处理器,8个内核)。
我很感激对此类行为的任何解释或建议如何才能获得更好的可扩展性(例如某些特定的jvm设置)。
编辑:我知道引入一些线程本地池来重用对象而不是每次都分配它应该可以提高可伸缩性。但它只是解决方法(我目前正在尝试实施)。我实际上想在这两个问题上找到答案:1)为什么提供的测试不可扩展? 2)如果不是硬件限制,如何在没有代码更改的情况下使jvm高效工作?
答案 0 :(得分:0)
看起来分配速度非常接近我的RAM的理论最大值。 Java甚至在1个线程中也达到了它,所以线程越多越好。此外,我发现我的PC配置为在单通道模式下使用内存(两个RAM模块安装在不同颜色的插槽中)。在双模式下,我观察到两次更好的结果。
P.S。谢谢大家的意见!