标签: jvm-hotspot

是否有一个Java字节码优化器,可以删除无用的gotos?

问题:我有一个方法可以编译超过8000字节的Java字节码.HotSpot有一个神奇的限制,使得JIT不会超过8000字节的方法.(是的,有一个庞大的方法是合理的.这是一个标记器循环.)该方法在库中,我不想要求库的用户必须配置HotSpot来停用魔术限制.

观察:反编译字节码表明Eclipse Java Compiler生成了许多无意义的getos.(javac甚至更糟.)也就是说,有些只能从跳跃中获得.显然,跳转到goto的跳转应该直接跳到goto跳转的地方,goto应该被消除.

问题:是否有针对Java 5类文件的字节码优化器,可以使无意义的跳转链变平,然后删除不必要的getos?

编辑:我的意思是:

8698:   goto    8548
8701:   goto    0
Run Code Online (Sandbox Code Playgroud)

显然,第二个goto只能通过跳转到8701到达,这可能也是直接跳转到0.

在第二次调查中,这种可疑模式更为常见:

4257:   if_icmpne   4263
4260:   goto    8704
4263:   aload_0
Run Code Online (Sandbox Code Playgroud)

显然,人们希望编译器将"不等于"比较反转为"相等"比较,跳转到8704并消除goto.

java optimization bytecode goto jvm-hotspot

18
推荐指数
1
解决办法
1659
查看次数

为什么在静态初始化器中使用并行流会导致不稳定的死锁

注意:这是不是重复,请仔细阅读题目сarefully /sf/users/241389361/报价:

真正的问题是为什么代码有时会起作用.即使没有lambdas,问题也会重现.这让我觉得可能存在JVM错误.

/sf/answers/3759645221/的评论中,我试图找出原因,为什么代码的行为从一个开始到另一个不同,并且该讨论的参与者给了我一些建议来创建一个单独的主题.

不要考虑以下源代码:

public class Test {
    static {
        System.out.println("static initializer: " + Thread.currentThread().getName());

        final long SUM = IntStream.range(0, 5)
                .parallel()
                .mapToObj(i -> {
                    System.out.println("map: " + Thread.currentThread().getName() + " " + i);
                    return i;
                })
                .sum();
    }

    public static void main(String[] args) {
        System.out.println("Finished");
    }
}
Run Code Online (Sandbox Code Playgroud)

有时(几乎总是)它会导致死锁.

输出示例:

static initializer: main
map: main 2
map: ForkJoinPool.commonPool-worker-3 4
map: ForkJoinPool.commonPool-worker-3 3
map: ForkJoinPool.commonPool-worker-2 0
Run Code Online (Sandbox Code Playgroud)

但有时它会成功完成(非常罕见):

static initializer: main
map: main 2
map: main …
Run Code Online (Sandbox Code Playgroud)

java concurrency deadlock jvm-hotspot static-initialization

18
推荐指数
1
解决办法
894
查看次数

当20%的堆仍然是免费的时,为什么我会得到OutOfMemory?

我已将最大堆设置为8 GB.当我的程序开始使用大约6.4 GB(在VisualVM中报告)时,垃圾收集器开始占用大部分CPU,并且在进行~100 MB分配时程序与OutOfMemory崩溃.我在Windows上使用Oracle Java 1.7.0_21.

我的问题是,是否有GC选项可以帮助解决这个问题.除了-Xmx8g,我没有传递任何东西.

我的猜测是堆已经碎片化了,但GC应该不紧凑吗?

java garbage-collection jvm-hotspot

17
推荐指数
1
解决办法
1346
查看次数

.NET运行时与Java热点:.NET一代落后了吗?

根据我可以收集的有关.NET和Java执行环境的信息,目前的情况如下:

抛开基准并且无意升级圣战,这是否意味着Java Hotspot VM比.Net领先一代.这些在Java VM中使用的技术最终是否会进入.NET运行时?

.net java comparison jit jvm-hotspot

16
推荐指数
3
解决办法
2518
查看次数

Java在许多内核上的扩展比C#差得多?

我正在测试在32核心服务器上为Java和C#运行相同功能的许多线程的产生.我使用函数的1000次迭代运行应用程序,使用线程池对1,2,4,8,16或32个线程进行批处理.

在1,2,4,8和16个并发线程中Java至少是C#的两倍.但是,随着线程数量的增加,间隙关闭,32个线程C#的平均运行时间几乎相同,但Java偶尔需要2000ms(而两种语言通常运行时间约为400ms).在每个线程迭代所花费的时间内,Java开始变得更糟.

编辑这是Windows Server 2008

EDIT2我已经使用Executor Service线程池更改了下面的代码.我还安装了Java 7.

我在热点VM中设置了以下优化:

-XX:+ UseConcMarkSweepGC -Xmx 6000

但它仍然没有让事情变得更好.代码之间的唯一区别是我使用下面的线程池和我们使用的C#版本:

http://www.codeproject.com/Articles/7933/Smart-Thread-Pool

有没有办法让Java更加优化?Perhaos你可以解释为什么我看到这种性能大幅下降?

是否有更高效的Java线程池?

(请注意,我不是指改变测试功能)

import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class PoolDemo {

    static long FastestMemory = 2000000;
    static long SlowestMemory = 0;
    static long TotalTime;
    static int[] FileArray;
    static DataOutputStream outs;
    static FileOutputStream fout;
    static Byte myByte = 0;

  public static void main(String[] args) throws InterruptedException, FileNotFoundException {

        int Iterations = Integer.parseInt(args[0]);
        int ThreadSize = Integer.parseInt(args[1]); …
Run Code Online (Sandbox Code Playgroud)

.net c# java eclipse jvm-hotspot

16
推荐指数
2
解决办法
1104
查看次数

Java8元空间和堆使用

我有这个代码动态生成类并加载它

import javassist.CannotCompileException;
import javassist.ClassPool;

public class PermGenLeak {
    private static final String PACKAGE_NAME = "com.jigarjoshi.permgenleak.";

    public static void main(String[] args) throws CannotCompileException, InterruptedException {
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            ClassPool pool = ClassPool.getDefault();
            pool.makeClass(PACKAGE_NAME + i).toClass();
            Thread.sleep(3);
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

我针对Java 7(jdk1.7.0_60)启动了这个类,正如预期的那样,它填满了PermGenSpace并且堆仍未使用 Java 7内存使用情况 图像显示permgen使用超时,最后JVM终止

现在相同的代码针对Java 8(jdk1.8.0_40-ea)运行并且正如预期的那样它继续扩展本机内存(Metaspace)但令人惊讶的是,1g的Metaspace它在OldGen中消耗了3g的堆(随着时间的推移,几乎是Metaspace的3倍)

Java8内存使用情况 该图显示了Metaspace使用超时和系统内存使用示例

这封来自Jon Masamitsu的电子邮件这张JEP门票

interned String和Class stats以及一些misc数据已移至Heap

当它将更多类加载到Metaspace中时,究竟是什么导致了堆的增加?

java jvm jvm-hotspot java-8 metaspace

16
推荐指数
1
解决办法
7034
查看次数

Hotspot JIT编译器是否可以重现任何指令重新排序?

我们知道,一些JIT允许重新排序对象初始化,例如,

someRef = new SomeObject();
Run Code Online (Sandbox Code Playgroud)

可以分解为以下步骤:

objRef = allocate space for SomeObject; //step1
call constructor of SomeObject;         //step2
someRef = objRef;                    //step3
Run Code Online (Sandbox Code Playgroud)

JIT编译器可能会重新排序如下:

objRef = allocate space for SomeObject; //step1
someRef = objRef;                    //step3
call constructor of SomeObject;         //step2
Run Code Online (Sandbox Code Playgroud)

即,步骤2和步骤3可以由JIT编译器重新排序.虽然这在理论上是有效的重新排序,但我无法使用x86平台下的Hotspot(jdk1.7)重现它.

那么,Hotspot JIT comipler是否可以重现任何指令重新排序?


更新:我使用以下命令在我的机器(Linux x86_64,JDK 1.8.0_40,i5-3210M)上进行了测试:

java -XX:-UseCompressedOops -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand="print org.openjdk.jcstress.tests.unsafe.UnsafePublication::publish" -XX:CompileCommand="inline, org.openjdk.jcstress.tests.unsafe.UnsafePublication::publish" -XX:PrintAssemblyOptions=intel -jar tests-custom/target/jcstress.jar -f -1 -t .*UnsafePublication.* -v > log.txt 
Run Code Online (Sandbox Code Playgroud)

我可以看到该工具报告的内容如下:

[1] 5可接受对象已发布,至少有1个字段可见.

这意味着观察者线程看到了一个未初始化的MyObject实例.

但是,我没有看到像@ Ivan那样生成的汇编代码:

0x00007f71d4a15e34: mov r11d,DWORD PTR …
Run Code Online (Sandbox Code Playgroud)

java multithreading jit jvm jvm-hotspot

16
推荐指数
1
解决办法
581
查看次数

究竟什么被认为是垃圾收集根以及它们如何在HotSpot JVM中找到?

介绍:

在大学里,人们了解到Java(和类似语言)中的典型垃圾收集根是加载类的静态变量,当前运行线程的线程局部变量,"外部引用"(如JNI句柄)和GC特定(如old-to) -在世代垃圾收集器的Minor GCs期间的年轻指针.从理论上讲,这听起来并不难.


问题:

我读的热点的源代码和感兴趣的是如何在VM内检测到这些垃圾收集根,即,该方法是使用内部的JVM源代码访问所有的根源.


调查:

我发现psMarkSweep.cpp属于各种GC实现的各种文件(例如)包含非常相似的结构.

以下是我认为涵盖强大根源的方法PSMarkSweep::mark_sweep_phase1方法psMarkSweep.cpp:

ParallelScavengeHeap::ParStrongRootsScope psrs;    
Universe::oops_do(mark_and_push_closure());    
JNIHandles::oops_do(mark_and_push_closure());   // Global (strong) JNI handles    
CLDToOopClosure mark_and_push_from_cld(mark_and_push_closure());
MarkingCodeBlobClosure each_active_code_blob(mark_and_push_closure(), !CodeBlobToOopClosure::FixRelocations);    
Threads::oops_do(mark_and_push_closure(), &mark_and_push_from_cld, &each_active_code_blob);    
ObjectSynchronizer::oops_do(mark_and_push_closure());    
FlatProfiler::oops_do(mark_and_push_closure());    
Management::oops_do(mark_and_push_closure());    
JvmtiExport::oops_do(mark_and_push_closure());    
SystemDictionary::always_strong_oops_do(mark_and_push_closure());    
ClassLoaderDataGraph::always_strong_cld_do(follow_cld_closure());    
// Do not treat nmethods as strong roots for mark/sweep, since we can unload them. 
//CodeCache::scavenge_root_nmethods_do(CodeBlobToOopClosure(mark_and_push_closure()));    
Run Code Online (Sandbox Code Playgroud)

以下代码psScavenge.cpp似乎为不同类型的GC根添加任务:

if (!old_gen->object_space()->is_empty()) {
  // There are only old-to-young pointers …
Run Code Online (Sandbox Code Playgroud)

java garbage-collection jvm heap-memory jvm-hotspot

16
推荐指数
1
解决办法
679
查看次数

Java致命错误SIGSEGV

我从Java编译器收到一条我不明白的错误消息.我在OSX 10.6,10.9和Ubuntu 14.04上使用Java 6和7测试了我的代码.当我使用Eclipse调试器或解释器(使用-Xint选项)运行时,一切运行正常.否则,我收到以下消息:

Java 1.6:

Invalid memory access of location 0x8 rip=0x1024e9660
Run Code Online (Sandbox Code Playgroud)

Java 1.7:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x000000010f7a8262, pid=20344, tid=18179
#
# JRE version: Java(TM) SE Runtime Environment (7.0_60-b19) (build 1.7.0_60-b19)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (24.60-b09 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# V  [libjvm.dylib+0x3a8262]  PhaseIdealLoop::idom_no_update(Node*) const+0x12
#
# Failed to write core dump. Core dumps have been …
Run Code Online (Sandbox Code Playgroud)

java jvm-hotspot segmentation-fault jvm-crash

15
推荐指数
1
解决办法
1万
查看次数

简单地添加一个方法参数(更简洁的jit代码),无法解释的10%+性能提升

(注意:正确答案必须超越复制).

在数百万次调用之后,quicksort1肯定比quicksort2更快,除了这个额外的arg之外,它们具有相同的代码.

代码在帖子的末尾.Spoiler:我还发现jit代码比224字节更胖,即使它实际上应该更简单(如字节代码大小告诉;请参阅下面的最后更新).

即使试图用一些微基准线束(JMH)来解决这种影响,性能差异仍然存在.

我在问:为什么生成的本机代码存在这样的差异,它在做什么?

通过向方法添加参数,它使它更快......!我知道gc/jit/warmup/etc效果.您可以按原样运行代码,也可以使用更大/更小的迭代计数.实际上,你甚至应该注释掉一个然后另一个性能测试并在不同的jvm实例中运行它们,只是为了证明它不是彼此之间的干扰.

字节码没有显示出太大的区别,除了明显的getstatic为sleft/sright,还有一个奇怪的'iload 4'而不是"iload_3"(和istore 4/istore_3)

到底他妈发生了什么?iload_3/istore_3真的比iload 4/istore 4慢吗?即使添加的getstatic调用仍然没有让它变慢,那要慢得多?我猜测静态字段是未使用的,因此jit可能只是跳过它.

无论如何,我的方面没有任何歧义,因为它总是可重复的,我正在寻找解释为什么javac/jit做了他们所做的,以及为什么性能受到如此大的影响.这些是相同的递归算法,具有相同的数据,相同的内存流失等等...如果我愿意,我无法进行更加孤立的更改,以显示可重复的运行时差异.

ENV:

java version "1.8.0_161" 
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
(also tried and reproduced on java9)
on a 4 core i5 laptop 8GB ram.
windows 10 with the meltdown/specter patch.
Run Code Online (Sandbox Code Playgroud)

使用-verbose:gc -XX:+ PrintCompilation,没有gc和jit编译在C2(第4层)中已经稳定.

n = 20000时:

main]: qs1: 1561.3336199999999 ms (res=null)
main]: qs2: 1749.748416 ms (res=null)

main]: qs1: 1422.0767509999998 ms (res=null)
main]: qs2: 1700.4858689999999 ms (res=null)

main]: qs1: …
Run Code Online (Sandbox Code Playgroud)

java jit bytecode jvm-hotspot hotspot

15
推荐指数
2
解决办法
989
查看次数