这究竟是为什么呢?都说JVM能实际使用的内存比-Xmx指定的少,头大
这确实是个挺奇怪的问题,特别是解析当最常出现的几种解释理由都被排除后,看来JVM并没有耍一些明显的源码小花招:
要弄清楚这个问题的第一步就是要明白这些工具的实现原理。通过标准APIs,解析礼金多多指标源码我们可以用以下简单语句得到可使用的内存信息。
而且确实,源码现有检测工具底层也是解析用这个语句来进行检测。要解决这个问题,源码首先我们需要一个可重复使用的解析测试用例。因此,源码我写了下面这段代码:
这段代码通过将new int[1__]置于一个循环中来不断分配内存给程序,解析然后监测JVM运行期的源码道游源码免费当前可用内存。当程序监测到可用内存大小发生变化时,解析通过打印出Runtime.getRuntime().maxMemory()返回值来得到当前可用内存尺寸,源码输出类似下面语句:
实际情况也确实如预估的解析那样,尽管我已经给JVM预先指定分配了2G对内存,源码在不知道为什么在运行期有M内存不见了。优质的直播源码你大可以把 Runtime.getRuntime().maxMemory()的返回值2,,K 除以来转换成MB,那样你将得到1,M,正好和M差M。
在成功重现了这个问题之后,我尝试用使用不同的asp发布站源码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算法,这个差值可能有所不同。
javaå¹³å°å¯¹äºè½¯ä»¶å¼åç¼ç¨çå½±åä½ç¨ï¼
éçäºèç½çä¸æåå±ï¼javaç¼ç¨è¯è¨ç严谨æ§åå®æ´æ§é½å¾å°äºå¤§å¹ 度çæåãä»å¤©ï¼çµèå¹è®å°±ä¸èµ·æ¥äºè§£ä¸ä¸ï¼å ³äºjavaç¼ç¨çä¸äºå ¶ä»ç¥è¯ä½ç³»ãå¸æéè¿å¯¹æ¬æçé 读ï¼å¤§å®¶è½å¤æ¸ æ¥çäºè§£javaç¼ç¨è¯è¨çå¼åææ¯ç¥è¯ãJavaæ¬èº«æ¯ä¸ç§é¢å对象çè¯è¨ï¼æ¾èçç¹æ§æ两个æ¹é¢ï¼ä¸æ¯æè°çâä¸æ¬¡ç¼è¯ï¼å°å¤æ§è¡â(Compileonce,runanywhere)ï¼è½å¤é常容æå°è·å¾è·¨å¹³å°è½å;å¦å¤å°±æ¯åå¾æ¶é(GC,GarbageCollection)ï¼Javaéè¿åå¾æ¶éå¨(GarbageCollector)åæ¶åé å åï¼å¤§é¨åæ åµä¸ï¼ç¨åºåä¸éè¦èªå·±æå¿å åçåé ååæ¶ã
æ们æ¥å¸¸ä¼æ¥è§¦å°JRE(JavaRuntimeEnvironment)æè JDK(JavaDevelopmentKit)ãJREï¼ä¹å°±æ¯Javaè¿è¡ç¯å¢ï¼å å«äºJVMåJavaç±»åºï¼ä»¥åä¸äºæ¨¡åçãèJDKå¯ä»¥çä½æ¯JREçä¸ä¸ªè¶ éï¼æä¾äºæ´å¤å·¥å ·ï¼æ¯å¦ç¼è¯å¨ãåç§è¯æå·¥å ·çã
对äºâJavaæ¯è§£éæ§è¡âè¿å¥è¯ï¼è¿ä¸ªè¯´æ³ä¸å¤ªåç¡®ãæ们å¼åçJavaçæºä»£ç ï¼å éè¿Javacç¼è¯æ为åèç (bytecode)ï¼ç¶åï¼å¨è¿è¡æ¶ï¼éè¿Javaèææº(JVM)å åµç解éå¨å°åèç 转æ¢æ为ç»çæºå¨ç ãä½æ¯å¸¸è§çJVMï¼æ¯å¦æ们大å¤æ°æ åµä½¿ç¨çOracleJDKæä¾çHospotJVMï¼é½æä¾äºJIT(Just-In-Time)ç¼è¯å¨ï¼ä¹å°±æ¯é常æ说çå¨æç¼è¯å¨ï¼JITè½å¤å¨è¿è¡æ¶å°çç¹ä»£ç ç¼è¯ææºå¨ç ï¼è¿ç§æ åµä¸é¨åçç¹ä»£ç å°±å±äºç¼è¯æ§è¡ï¼èä¸æ¯è§£éæ§è¡äºã
对äºJavaå¹³å°çç解ï¼å¯ä»¥ä»å¾å¤æ¹é¢ç®ææ¼è¦å°è°ä¸ä¸ï¼ä¾å¦ï¼Javaè¯è¨ç¹æ§ï¼å æ¬æ³åãLambdaçè¯è¨ç¹æ§;åºç¡ç±»åºï¼å æ¬éåãIO/NIOãç½ç»ã并åãå®å ¨çåºç¡ç±»åºã对äºæ们æ¥å¸¸å·¥ä½åºç¨è¾å¤çç±»åºï¼é¢è¯åå¯ä»¥ç³»ç»åæ»ç»ä¸ä¸ï¼æå©äºä¸´åºåæ¥ã
æè è°è°JVMçä¸äºåºç¡æ¦å¿µåæºå¶ï¼æ¯å¦Javaçç±»å è½½æºå¶ï¼å¸¸ç¨çæ¬JDK(å¦JDK8)å åµçClass-Loaderï¼ä¾å¦BootstrapãApplicationåExtensionClass-loader;ç±»å 载大è´è¿ç¨ï¼å è½½ãéªè¯ãé¾æ¥ãåå§å(è¿éåèäºå¨å¿æçãæ·±å ¥ç解Javaèææºãï¼é常æ£çJVMä¸æ书ç±);èªå®ä¹Class-Loaderçãè¿æåå¾æ¶éçåºæ¬åçï¼å¸¸è§çåå¾æ¶éå¨ï¼å¦SerialGCãParallelGCãCMSãG1çï¼å¯¹äºéç¨äºä»ä¹æ ·çå·¥ä½è´è½½å¥½ä¹å¿éææ°ãè¿äºé½æ¯å¯ä»¥æ©å±å¼çé¢åï¼æä¼å¨åé¢çä¸æ 对æ¤è¿è¡æ´ç³»ç»çä»ç»ã
å½ç¶è¿æJDKå å«åªäºå·¥å ·æè Javaé¢åå å ¶ä»å·¥å ·çï¼å¦ç¼è¯å¨ãè¿è¡æ¶ç¯å¢ãå®å ¨å·¥å ·ãè¯æåçæ§å·¥å ·çãè¿äºåºæ¬å·¥å ·æ¯æ¥å¸¸å·¥ä½æççä¿è¯ï¼å¯¹äºæ们工ä½å¨å ¶ä»è¯è¨å¹³å°ä¸ï¼åæ ·ææ帮å©ï¼å¾å¤é½æ¯è§¦ç±»æéçã
2024-12-23 07:00
2024-12-23 06:45
2024-12-23 05:26
2024-12-23 05:15
2024-12-23 04:54