1.这究竟是源码为什么呢?都说JVM能实际使用的内存比-Xmx指定的少,头大
2.javaå¹³å°å¯¹äºè½¯ä»¶å¼åç¼ç¨çå½±åä½ç¨ï¼
这究竟是为什么呢?都说JVM能实际使用的内存比-Xmx指定的少,头大
这确实是个挺奇怪的问题,特别是解析当最常出现的几种解释理由都被排除后,看来JVM并没有耍一些明显的源码小花招:
要弄清楚这个问题的第一步就是要明白这些工具的实现原理。通过标准APIs,解析orb描述子源码我们可以用以下简单语句得到可使用的内存信息。
而且确实,源码现有检测工具底层也是解析用这个语句来进行检测。要解决这个问题,源码首先我们需要一个可重复使用的解析测试用例。因此,源码我写了下面这段代码:
这段代码通过将new int[1__]置于一个循环中来不断分配内存给程序,解析然后监测JVM运行期的源码android 漫画app源码当前可用内存。当程序监测到可用内存大小发生变化时,解析通过打印出Runtime.getRuntime().maxMemory()返回值来得到当前可用内存尺寸,源码输出类似下面语句:
实际情况也确实如预估的解析那样,尽管我已经给JVM预先指定分配了2G对内存,源码在不知道为什么在运行期有M内存不见了。ubuntu源码编译安装你大可以把 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算法,这个差值可能有所不同。
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é¢åå å ¶ä»å·¥å ·çï¼å¦ç¼è¯å¨ãè¿è¡æ¶ç¯å¢ãå®å ¨å·¥å ·ãè¯æåçæ§å·¥å ·çãè¿äºåºæ¬å·¥å ·æ¯æ¥å¸¸å·¥ä½æççä¿è¯ï¼å¯¹äºæ们工ä½å¨å ¶ä»è¯è¨å¹³å°ä¸ï¼åæ ·ææ帮å©ï¼å¾å¤é½æ¯è§¦ç±»æéçã