皮皮网
皮皮网

【做好趋势主图指标源码】【虚拟精灵源码】【eva源码学习】jvm计算源码_jvm 源码分析

来源:小型mysql源码 发表时间:2024-11-28 15:50:31

1.如何计算java对象占用的内存
2.OpenJDK17-JVM 源码阅读 - ZGC - 并发标记 | 京东物流技术团队
3.这究竟是算源为什么呢?都说JVM能实际使用的内存比-Xmx指定的少,头大
4.jvm如何在运行时动态把java文本编译成class,然后加载到jvm

jvm计算源码_jvm 源码分析

如何计算java对象占用的内存

       Java有一个很好的地方就是java的垃圾收集机制,这个机制集成于jvm的,对程序员来说是隐藏且不透明的。这种情况下,如何得到某个对象消耗的内存呢?

       ã€€ã€€

       ã€€ã€€ã€€ã€€æ›¾ç»çœ‹åˆ°è¿‡æœ‰äººç”¨ä»¥ä¸‹æ–¹æ³•æ¥è®¡ç®—:在生成该object的前后都调用java.lang.Runtime.freeMemory()方法,然后看两者之差即为该object消耗的内存量。

       ã€€ã€€

       ã€€ã€€ã€€ã€€è¿™ç§æ–¹æ³•çš„代码是:

       ã€€ã€€

       ã€€ã€€long totalMem = java.lang.Runtime.freeMemory();

       ã€€ã€€Object myBigObject = null;

       ã€€ã€€System.out.println("You just got rid of " + totalMem

       ã€€ã€€ - java.lang.Runtime.freeMemory());

       ã€€ã€€

       ã€€ã€€

       ã€€ã€€

       ã€€ã€€ã€€ã€€è¿™ç§æƒ³æ³•æ˜¯å¯¹çš„,但是实际上,jvm的freememory往往不能正确反应实际的free

        memory。比如在jvm要进行垃圾收集的时候,free

       memory就会缩小。而如果决定垃圾收集的时间发生在该object生成之后,而在第二次调用java.lang.Runtime.freeMemory()之前,那么就会错误地增加该object消耗的内存量。

       ã€€ã€€

       ã€€ã€€ã€€ã€€åœ¨java专家By

        Tony Sintes的文章"Discover how much memory an object consumes "

       é‡Œé¢æåˆ°äº†åº”该用Runtime.getRuntime().totalMemory();并且计算两次之差来得到消耗的内存量。

       ã€€ã€€

       ã€€ã€€ã€€ã€€By Tony Sintes的源代码:

       ã€€ã€€

       ã€€ã€€public class Memory {

       ã€€ã€€ private final static int _SIZE = ;

       ã€€ã€€ public static void main( String [] args )

       ã€€ã€€ throws Exception {

       ã€€ã€€ Object[] array = new Object[_SIZE];

       ã€€ã€€ Runtime.getRuntime().gc();

       ã€€ã€€ long start = Runtime.getRuntime().totalMemory();

       ã€€ã€€ for (int i = 0; i < _SIZE; i++) {

       ã€€ã€€ array[i] = new Object();

       ã€€ã€€ }

       ã€€ã€€ Runtime.getRuntime().gc();

       ã€€ã€€ long end = Runtime.getRuntime().totalMemory();

       ã€€ã€€ long difference = ( start - end ) / _SIZE;

       ã€€ã€€ System.out.println( difference + " bytes used

       ã€€ã€€ per object on average" );

       ã€€ã€€ }

       ã€€ã€€}

       ã€€ã€€

       ã€€ã€€

       ã€€ã€€

       ã€€ã€€ã€€ã€€å®žé™…上,这种方法基本上正确了,但是By Tony Sintes疏忽了一点,就是仅仅Runtime.getRuntime().gc();并不能真正完成垃圾收集,也就是说实际上jvm的内存此时并不是稳定的。

       ã€€ã€€

       ã€€ã€€ã€€ã€€æ‰€ä»¥ï¼Œåªæœ‰å½“内存不再发生大的变动,或者说已经稳定,我们才可能说垃圾收集已经完成。

       ã€€ã€€

       ã€€ã€€ã€€ã€€å¦‚何才能真正确保基本完成了jvm的垃圾收集呢?实现这个功能的代码如下:

       ã€€ã€€

       ã€€ã€€private static final Runtime s_runtime =

       ã€€ã€€ Runtime.getRuntime ();

       ã€€ã€€private static long usedMemory ()

       ã€€ã€€ {

       ã€€ã€€ return s_runtime.totalMemory () -

       ã€€ã€€ s_runtime.freeMemory ();

       ã€€ã€€ }

       ã€€ã€€private static void runGC () throws Exception

       ã€€ã€€ {

       ã€€ã€€long usedMem1 = usedMemory (), usedMem2 = Long.MAX_value;

       ã€€ã€€for (int i = 0; (usedMem1 < usedMem2) && (i < ); ++ i)

       ã€€ã€€ {

       ã€€ã€€ s_runtime.runFinalization ();

       ã€€ã€€ s_runtime.gc ();

       ã€€ã€€ Thread.currentThread ().yield ();

       ã€€ã€€ usedMem2 = usedMem1;

       ã€€ã€€ usedMem1 = usedMemory ();

       ã€€ã€€ }

       ã€€ã€€ }

OpenJDK-JVM 源码阅读 - ZGC - 并发标记 | 京东物流技术团队

       ZGC简介:

       ZGC是Java垃圾回收器的前沿技术,支持低延迟、源码大容量堆、分析染色指针、算源读屏障等特性,源码自JDK起作为试验特性,分析做好趋势主图指标源码JDK起支持Windows,算源JDK正式投入生产使用。源码在JDK中已实现分代收集,分析预计不久将发布,算源性能将更优秀。源码

       ZGC特征:

       1. 低延迟

       2. 大容量堆

       3. 染色指针

       4. 读屏障

       并发标记过程:

       ZGC并发标记主要分为三个阶段:初始标记、分析并发标记/重映射、算源重分配。源码虚拟精灵源码本篇主要分析并发标记/重映射部分源代码。分析

       入口与并发标记:

       整个ZGC源码入口是ZDriver::gc函数,其中concurrent()是一个宏定义。并发标记函数是concurrent_mark。

       并发标记流程:

       从ZHeap::heap()进入mark函数,使用任务框架执行任务逻辑在ZMarkTask里,具体执行函数是work。工作逻辑循环从标记条带中取出数据,直到取完或时间到。此循环即为ZGC三色标记主循环。之后进入drain函数,从栈中取出指针进行标记,直到栈排空。eva源码学习标记过程包括从栈取数据,标记和递归标记。

       标记与迭代:

       标记过程涉及对象迭代遍历。标记流程中,ZGC通过map存储对象地址的finalizable和inc_live信息。map大小约为堆中对象对齐大小的二分之一。接着通过oop_iterate函数对对象中的指针进行迭代,使用ZMarkBarrierOopClosure作为读屏障,实现了指针自愈和防止漏标。

       读屏障细节:

       ZMarkBarrierOopClosure函数在标记非静态成员变量的指针时触发读屏障。慢路径处理和指针自愈是核心逻辑,慢路径标记指针,快速路径通过cas操作修复坏指针,源码软测并重新标记。

       重映射过程:

       读屏障触发标记后,对象被推入栈中,下次标记循环时取出。ZGC并发标记流程至此结束。

       问题回顾:

       本文解答了ZGC如何标记指针、三色标记过程、如何防止漏标、指针自愈和并发重映射过程的问题。

       扩展思考:

       ZGC在指针上标记,当回收某个region时,如何得知对象是否存活?答案需要结合标记阶段和重分配阶段的代码。

       结束语:

       本文深入分析了ZGC并发标记的廊坊源码时代源码细节,对您有启发或帮助的话,请多多点赞支持。作者:京东物流 刘家存,来源:京东云开发者社区 自猿其说 Tech。转载请注明来源。

这究竟是为什么呢?都说JVM能实际使用的内存比-Xmx指定的少,头大

       这确实是个挺奇怪的问题,特别是当最常出现的几种解释理由都被排除后,看来JVM并没有耍一些明显的小花招:

       要弄清楚这个问题的第一步就是要明白这些工具的实现原理。通过标准APIs,我们可以用以下简单语句得到可使用的内存信息。

       而且确实,现有检测工具底层也是用这个语句来进行检测。要解决这个问题,首先我们需要一个可重复使用的测试用例。因此,我写了下面这段代码:

       这段代码通过将new int[1__]置于一个循环中来不断分配内存给程序,然后监测JVM运行期的当前可用内存。当程序监测到可用内存大小发生变化时,通过打印出Runtime.getRuntime().maxMemory()返回值来得到当前可用内存尺寸,输出类似下面语句:

       实际情况也确实如预估的那样,尽管我已经给JVM预先指定分配了2G对内存,在不知道为什么在运行期有M内存不见了。你大可以把 Runtime.getRuntime().maxMemory()的返回值2,,K 除以来转换成MB,那样你将得到1,M,正好和M差M。

       在成功重现了这个问题之后,我尝试用使用不同的GC算法,果然检测结果也不尽相同。

       除了G1算法刚好完整使用了我预指定分配的2G之外,其余每种GC算法似乎都不同程度地丢失了一些内存。

       现在我们就该看看在JVM的源代码中有没有关于这个问题的解释了。我在CollectedHeap这个类的源代码中找到了如下的解释:

       我不得不说这个答案藏得有点深,但是只要你有足够的好奇心,还是不难发现的:有时候,有一块Survivor区是不被计算到可用内存中的。

       明白这一点之后问题就好解决了。打开并查看GC logging 信息之后我们发现,在Serial,Parallel以及CMS算法回收过程中丢失的那些内存,尺寸刚好等于JVM从2G堆内存中划分给Survivor区内存的尺寸。例如,在上面的ParallelGC算法运行时,GC logging信息如下:

       由上面的信息可以看出,Eden区被分配了,K,两个Survivor区都被分配到了,K,老年代(Old space)则被分配了1,,K。把Eden区、老年代以及一个Survivor区的尺寸求和,刚好等于2,,K,说明丢失的那M(,K)确实就是剩下的那个Survivor区。

       总结而言,当JVM在运行时报告的可使用内存小于-Xmx指定的内存时,差值通常对应于一块Survivor区的大小。对于不同的GC算法,这个差值可能有所不同。

jvm如何在运行时动态把java文本编译成class,然后加载到jvm

       为了在Java程序运行时动态编译Java源代码并生成Class文件,避免将编译产物存到文件中,可以采用特殊的方法,例如自定义实现JavaFileManager和JavaFileObject。这类操作较为复杂,但提供了一种灵活的解决方案。

       实现策略可以分为两步:首先在运行时编译Java源代码,获取编译后的字节码;其次,使用自定义类加载器在运行时定义这些类。通过这种方式,无需文件操作,直接在内存中完成编译与加载过程。

       在使用编译器API进行动态编译时,可以遵循上述步骤。涉及的关键类JavaFileManager和JavaFileObject需要自定义实现,以满足特定的文件管理需求。

       然而,在尝试使用Java环境下运行上述代码时,可能会遇到编译失败的问题,而Java8环境下则能正常运行。具体原因尚未查明,可能涉及Java版本的兼容性或API实现细节的变动。

相关栏目:热点