Tag: jvm

JVM JIT诊断工具和优化技巧

我听到很多关于JVM JIT 可以做什么,但是没有看到很多关于如何分析JIT在程序的给定运行中实际执行的操作的信息。 有很多关于使用-XX:+PrintCompilation和-XX:+PrintOptoAssembly但它会导致很难解释的真正低级别的信息。 一般来说,在优化期间,我喜欢使用具有专用JIT预热时间等的常用操作的基准套件,但我希望能够看到哪些优化实际上触发了我的代码。 也许我的JVM考虑内联一个特定的方法调用,但它的一些东西使它决定不,或者JIT无法避免我的循环中的数组边界检查,因为我的措辞我的不变量和循环条件太模糊。 我希望像YourKit这样的工具能够支持某些forms的“JIT正在发生的事情”,但我无法在YourKit或其他任何地方找到支持。 理想情况下,我只是喜欢在我的程序运行期间JIT优化器正在思考的大脑转储。 假设我已经充分预热了我的function,它决定将三个方法内联到我的内循环中并将循环分成三个部分,中间部分没有数组边界检查,我想要总结这些决定和动机对他们来说 我错过了一些明显的东西吗? JVM性能感知程序员在优化紧密内循环以确定正在发生的事情时会做些什么? 当然,低级-XX标志不是唯一的选择,可以吗? 我很欣赏有关如何最好地处理JVM上的这种低级内容的提示。 不,这个问题不是因为过早优化而产生的! 🙂 编辑:我想我想要的一些东西是由-XX:+LogCompilation给出的,但是如果人们有这种活动的一般提示和工具,我仍然很好奇。

在Java中加载类时如何管理内存?

想象一下,我有一个包含10个方法的类,我需要从类中实例化10个对象。 问题是: JVM是否会在对象创建时为10个实例分配10个不同的内存空间(我的意思是在我调用构造函数时,即新的MyClass();?或者它将在内存和每个实例中调用类定义一次这10个方法中的每一个,在运行时,JVM都会分配内存吗? 为了清除一些误解,我的问题是在创建对象时,我知道所有数据成员都分配在堆内存中,但是我不确定尚未调用的方法是否在内存中为每个对象分配不同或者不?

了解JNI参数的安全访问

我正在研究HotSpot在JNI代码运行时如何执行垃圾收集和/或堆压缩。 似乎众所周知,可以随时在Java中移动对象。 我试图明白,如果JNI受到垃圾收集效果的影响。 存在许多JNI函数来明确地防止垃圾收集; 例如GetPrimitiveArrayCritical 。 如果引用确实是volatile,那么这样的函数是有意义的。 然而,如果他们不是,那就毫无意义。 关于这个问题似乎存在大量相互矛盾的信息,我正试图解决这个问题。 JNI代码在安全点运行并且可以继续运行,除非它回调到Java或调用某些特定的JVM方法,此时可以停止它以防止离开安全点(感谢Nitsan的注释)。 JVM在停止世界暂停期间用于阻止线程的机制 上面让我觉得垃圾收集将与JNI代码同时运行。 那不可能是安全的,对吗? 为了实现本地引用,Java VM为从Java到本机方法的每次控制转换创建了一个注册表。 注册表将不可移动的本地引用映射到Java对象,并防止对象被垃圾回收。 传递给本机方法的所有Java对象(包括那些作为JNI函数调用结果返回的对象)都会自动添加到注册表中。 在本机方法返回后删除注册表,允许其所有条目被垃圾回收。 https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html#wp16789 好的,所以local引用是不可移动的,但是没有说明压缩。 JVM必须确保将作为参数从Java™传递到本机方法的对象以及由本机代码创建的任何新对象仍可由GC访问。 为了处理GC要求,JVM分配一个称为“本地参考根集”的小型专用存储区域。 在以下情况下创建本地引用根集: 线程首先附加到JVM(线程的“最外层”根集)。 发生每个J2N转换。 JVM使用以下命令初始化为J2N转换创建的根集: 对调用者的对象或类的本地引用。 对作为参数传递给本机方法的每个对象的本地引用。 除非使用PushLocalFrame JNI函数创建新的“本地框架”,否则在本机代码中创建的新本地引用将添加到此J2N根集。 http://www.ibm.com/support/knowledgecenter/en/SSYKE2_5.0.0/com.ibm.java.doc.diagnostics.50/diag/understanding/jni_transitions_j2n.html 好的,所以IBM将传递的对象存储在local reference root set但它没有讨论内存压缩。 这只是说对象不会被垃圾收集。 GC可能随时决定是否需要压缩垃圾收集堆。 压缩涉及将对象从一个地址物理移动到另一个地址。 这些对象可能由JNI本地或全局引用引用。 为了允许安全地进行压缩,JNI引用不是指向堆的直接指针。 至少一个间接级别将本机代码与对象移动隔离开来。 如果本机方法需要获得对象内部的直接可寻址性,则情况会更复杂。 在需要对大型原始数组进行快速共享访问的情况下,直接寻址或固定堆的要求是典型的。 一个例子可能包括屏幕缓冲区。 在这些情况下,可以使用JNI关键部分,这对程序员提出了额外的要求,如JNI对这些函数的描述中所规定的那样。 有关详细信息,请参阅JNI规范。 GetPrimitiveArrayCritical返回Java™数组的直接堆地址,禁用垃圾收集,直到调用相应的ReleasePrimitiveArrayCritical。 GetStringCritical返回java.lang.String实例的直接堆地址,在调用ReleaseStringCritical之前禁用垃圾收集。 http://www.ibm.com/support/knowledgecenter/SSYKE2_6.0.0/com.ibm.java.doc.diagnostics.60/diag/understanding/jni_copypin.html 好的,所以IBM基本上说JNI传递的对象可以随时移动! HotSpot怎么样? GetArrayElements系列函数被记录为复制数组,或者将它们固定到位(并且这样做可以防止压缩垃圾收集器移动它们)。 它被记录为GetPrimitiveArrayCritical的更安全,限制性更小的替代方案。 但是,我想知道哪些虚拟机和/或垃圾收集器(如果有的话)实际固定数组而不是复制它们。 哪些VM或GC支持JNI固定? […]

是否有可能使java.lang.invoke.MethodHandle与直接调用一样快?

我正在比较MethodHandle::invoke和直接静态方法MethodHandle::invoke性能。 这是静态方法: public class IntSum { public static int sum(int a, int b){ return a + b; } } 这是我的基准: @State(Scope.Benchmark) public class MyBenchmark { public int first; public int second; public final MethodHandle mhh; @Benchmark @OutputTimeUnit(TimeUnit.NANOSECONDS) @BenchmarkMode(Mode.AverageTime) public int directMethodCall() { return IntSum.sum(first, second); } @Benchmark @OutputTimeUnit(TimeUnit.NANOSECONDS) @BenchmarkMode(Mode.AverageTime) public int finalMethodHandle() throws Throwable { […]

在java CMS gc日志中,’real’,’user’和’sys’是什么意思?

对于以下Java版本: OpenJDK版“1.6.0” OpenJDK运行时环境(版本1.6.0-b23) OpenJDK 64位服务器VM(内置20.0-b11,混合模式) 使用以下GC标记: -verbose:GC -XX:+ UseConcMarkSweepGC -XX:+ CMSClassUnloadingEnabled -XX:+ PrintGCDetails -XX:+ PrintGCDateStamps 我们得到的日志行如下: 2012-11-09T16:46:53.438-0100:[CMS-concurrent-mark:4.039 / 4.060 secs] [次:用户= 4.09 sys = 35.05,real = 4.06 secs] 最初的“4.039 / 4.060秒”应根据https://blogs.oracle.com/poonam/entry/understanding_cms_gc_logs表示并发标记总共需要4.039秒的cpu时间和4.060秒的挂起时间(包括其他线程的收益率) )。 但是用户,系统和实际值在这里意味着什么?

在java中找到系统的字节顺序

如果机器是bigindian或littleindian,我发现checkink算法(int C) int is_big_endian(void) { union { uint32_t i; char c[4]; } bint = {0x01020304}; return bint.c[0] == 1; } 我怎样才能在* java中找到这样的东西? *我不想使用内置的库,因为这是一个采访问题。我想在java中找到它。

64位OpenJDK 7/8中并发长写的值完整性保证

注意:此问题与volatile,AtomicLong或所描述的用例中的任何感知缺陷无关。 我试图certificate或排除的财产如下: 鉴于以下内容: 最近的64位OpenJDK 7/8(最好7位,但8位也有帮助) 多处理英特尔基础系统 一个非易失性的长原始变量 多个不同步的mutator线程 一个不同步的观察者线程 是否始终保证观察者会遇到由变异器线程写的完整值,或者是撕裂危险的单词? JLS:不确定 此属性对于32位基元和64位对象引用是存在的,但是对于long和double,JLS不保证: 17.7。 双primefaces和非primefaces的非primefaces处理: 出于Java编程语言存储器模型的目的,对非易失性long或double值的单次写入被视为两个单独的写入:每个32位一半写入一次。 这可能导致线程从一次写入看到64位值的前32位,而从另一次写入看到第二次32位的情况。 但是抱着你的马: […]为了效率,这种行为是特定于实现的; Java虚拟机的实现可以自由地以primefaces方式或分两部分执行对long和double值的写入。 鼓励实现Java虚拟机以避免在可能的情况下拆分64位值。 […] 因此,JLS 允许 JVM实现拆分64位写入,并鼓励开发人员相应地进行调整,但也鼓励 JVM实现者坚持使用64位写入。 我们还没有回答最新版本的HotSpot。 HotSpot JIT:谨慎的乐观 由于单词撕裂最有可能发生在紧密循环和其他热点的范围内,我试图分析JIT编译的实际汇编输出。 简而言之:需要进一步测试,但我只能在long上看到primefaces64位操作。 我使用了hdis ,一个OpenJDK的反汇编插件。 在我老化的OpenJDK 7u25版本中构建并安装了该插件后,我开始编写一个简短的程序: public class Counter { static long counter = 0; public static void main(String[] _) { for (long i = (long)1e12; i […]

向java.lang.Object添加一个字段

我在Object类中添加了一个字段,如: class Object { … private Object _objInfo; } 我更改了java.lang.Object的源代码并重新编译了OpenJDK 6.当VM启动时,我收到以下exception: Error occurred during initialization of VM java.lang.IllegalStateException at java.lang.Throwable.initCause(Throwable.java:337) at java.lang.ExceptionInInitializerError.(ExceptionInInitializerError.java:79) 当我定义自己的Object类并将其添加到bootclasspath时会出现同样的问题,如: java -Xbootclasspath/p: 谢谢,Horatiu

如何在Java 7中实现多捕获?

Java 7编译器如何处理多捕获块? 一个简单的实现是生成字节码,就好像存在多个catch块一样。 但是,我从多个来源收集到的情况并非如此 – 处理多个exception类型的catch块在编译期间不会产生重复的字节码。 那么它是怎样工作的 ? 是否有新的字节码指令告诉JVM多捕获块?

如何获取唯一的JVM标识符?

Java代码如何为运行它的JVM获取唯一标识符? 在Unix系统上,我正在寻找的一个例子是运行JVM的进程的PID(假设JVM和进程之间的一对一映射)。