1.idea编译java后中文乱码怎么解决
2.分享一个调试Java程序生产问题工具:Lightrun
3.《面试1v1》JVM调试
4.jvmè°è¯å·¥å
·ç±»ä½¿ç¨ (jvisualvm.exe)
5.JVM角度看方法调用-MethodHandle篇
6.这究竟是码调为什么呢?都说JVM能实际使用的内存比-Xmx指定的少,头大
idea编译java后中文乱码怎么解决
解决IDEA编译Java后中文乱码问题的方法:一、确保源码文件编码正确
在编写Java代码时,码调确保你的码调源码文件编码为UTF-8。IDEA可以自动识别文件编码,码调但有时需要手动设置或检查。码调可以通过查看文件状态栏来确认编码。码调溯源码如何验证如果不是码调UTF-8,建议将文件另存为UTF-8编码格式。码调
二、码调检查项目编码设置
在IDEA中,码调你需要检查项目的码调编码设置。在项目的码调根目录下,右击选择“Mark Directory as”然后选择“Sources Root”。码调确保在“File Encoding”设置中选择了正确的码调编码方式,通常为UTF-8。码调这样可以确保IDEA在处理项目文件时使用正确的编码。
三、检查JVM编码设置
在编译和运行Java程序时,要确保JVM使用正确的字符编码。可以通过在命令行参数中设置JVM的默认字符编码来解决乱码问题。例如,在启动Java程序时,使用`-Dfile.encoding=UTF-8`参数来指定UTF-8编码。
四、检查控制台输出编码
如果在控制台输出中出现了乱码,可能是因为控制台使用的编码与程序输出的编码不一致。可以尝试修改IDEA控制台输出的编码设置。在IDEA的“Run”菜单中,选择“Edit Configurations”,然后在相应配置下设置“VM options”,添加或修改编码相关的参数。
综上所述,博弈娱乐源码城解决IDEA编译Java后中文乱码问题,主要需要从源码文件编码、项目编码设置、JVM编码设置以及控制台输出编码等方面进行检查和调整。确保所有涉及编码的地方都使用正确的UTF-8编码,可以有效解决中文乱码问题。
分享一个调试Java程序生产问题工具:Lightrun
在本文中,我将分享 Lightrun,这是我最近在开发RevoGain时发现的一个非常有用的工具,用于调试生产中出现的问题。
Lightrun提供了动态日志记录、运行时快照和动态指标等功能,允许我们在运行时动态插入日志条目、捕获快照,甚至在不更改生产代码的情况下注入指标,这在调查客户报告的问题时特别有用。
设置Lightrun非常简单,配置它只需要不到5分钟。对于本地Windows环境,可以通过代理提供。对于生产系统,可以使用基于Linux的命令。动态日志记录允许我们添加消息,并通过定义过滤条件来控制是否记录该消息。
在解析交易报表时,如果交易余额加起来不出来,需要具有交易对账单。添加动态日志条目将帮助我们在用户执行可以复制问题的操作时发现问题。通过定义特定条件,如id值为1的用户,可以仅显示特定消息。群发猫源码 香港
查看如何根据我们从对账单中解析的交易操作计算余额。如果计算的余额与语句提供的余额值不匹配,我们可以向客户确定导致问题的原因。没有Lightrun,我们不能只是调试生产系统,因为整个服务器将停止,从而影响可用性。
除了动态日志记录,Lightrun还提供了运行时快照功能,这些快照包含堆栈跟踪和拍摄快照时可用的变量。这可以帮助我们一次聚合多个信息,而不必使用单个日志。
我们还可以动态添加指标,而无需更改我们正在监控的源代码。例如,我使用此功能来计算使用 Stop Forum Spam API验证电子邮件地址需要多长时间。这很重要,因为我正在为我的客户提供实时聊天,我可以在我们的实时对话中调试他们的生产问题。
Lightrun易于使用,但功能非常强大,因为它允许我们使用指标注入日志、收集快照或检测我们的代码,而无需更改需要重新部署的生产源代码。这有助于我为客户提供卓越的支持。
更多与Java性能工具相关的内容,包括JVM调优工具、顶级Java才懂的长尾请求hack工具、使用JDK中自带的JVM分析工具解决内存溢出问题、如何使用Eclipse内存分析工具定位内存泄漏、排查死锁的柚子影视源码在哪4种工具、用crash工具分析Linux内核死锁的一次实战、6个Java工具轻松分析定位JVM问题、JVM源码分析之jstat工具原理完全解读、如何使用JVisualVM进行故障排查以及学会这个Thread Dump分析工具,让您秒变性能分析大师等。
《面试1v1》JVM调试
我叫 javapub,一名Markdown程序员兼八股文种子选手。在一次面试中,面试官向我提问关于JVM调优的掌握程度。我首先对JVM调优的理解进行了谦虚的描述,承认自己还在学习阶段,但日常工作中有接触JVM参数与监控工具,算是有入门水平。
面试官接着询问了我对JVM调优具体的方法和手段。我回答,JVM调优主要通过调整JVM参数和使用监控工具来进行。我日常工作中最常用的JVM参数和监控工具,帮助我在日常的JVM调优和问题排查中发挥了很大作用。尽管如此,我还需要继续深入学习JVM调优的更深层次理论和实践。
面试官对我的回答给予了肯定,认为我已经掌握了JVM调优的基础知识和日常工具的使用,是一个不错的入门水平。随后,面试官又问到了我作为JVM调优的进阶学习计划。我详细地介绍了我的学习计划,包括深入学习JVM调优的理论知识、实践技能等,需要通过不断学习和实践来提升。
最近,我正在更新《面试1v1》系列文章,各种选股源码以场景化的方式讲解在面试中遇到的问题,旨在帮助工程师们拿到心仪的offer。文章内容涵盖了JVM调优、数据结构与算法、Mybatis、搜索LuceneElasticsearch、Spring等技术点,以对话的形式、口语化描述技术点,涉及高频面试题、工作中如何使用,还穿插了部分源码解析。
《面试1v1》文章通过真实的面试场景模拟,帮助候选人如何自然地对答,避免紧张导致的知识点遗忘。文章以实际面试情况编写,使用大白话描述技术难题,避免背诵式回答。读者可以在这里找到面试中常考的知识点,甚至一些源码细节,以更好地准备面试。
《面试1v1》文章由我完全免费提供,并持续更新中。读者可以通过搜索“JavaPub”直接查看全系列文章。我将根据读者反馈和市场需要,持续更新和改进《面试1v1》系列文章,以帮助更多工程师们掌握面试技巧,顺利拿到心仪的offer。
如果你对《面试1v1》系列文章感兴趣,欢迎关注我 @JavaPub,获取最新的文章更新和学习资源。希望我的分享能够帮助你在面试中表现出色,实现职业发展的目标。
jvmè°è¯å·¥å ·ç±»ä½¿ç¨ (jvisualvm.exe)
ç®æ ï¼ä½¿ç¨JDKèªå¸¦çJVMçæµå·¥å ·è°è¯å å使ç¨æ åµåå æ é®é¢ææ¥ç®è¦è¯´æï¼å¨å®é 项ç®å¼åè¿ç¨ä¸ï¼å¦æ使ç¨å¤çº¿ç¨ï¼ä½æ¯æ²¡ææ§å¶å¥½çº¿ç¨æ°éçæ åµä¸ï¼å°±ä¼åºç°å å å溢åºé®é¢ï¼å¯¼è´åè½æå¡å®æºï¼å¦æ严éå¾å¯è½å¯¼è´æå¡å¨å®æºé®é¢ãå½åºç°å å溢åºæ¶ï¼åªè½çå°ç®åçå å溢åºæ¥å¿ï¼ææ¥é®é¢æ¯«æ 头绪ï¼ä¸ç¥éåªé线ç¨åºç°é®é¢ï¼è¿æ ·å°±å¾é¾è§£å³é®é¢ï¼
è¿æ¶æ们就å¯ä»¥éè¿JDKèªå¸¦çJVMçæ§å·¥å ·æ¥çæ¯ä¸ªçº¿ç¨ççå½å¨æ以åç¸å ³æºç 追溯ï¼è¿æ ·å°±å¯ä»¥æ¸ æ¥æäºççæ¸ é®é¢åºç°å¨åªéï¼ç¶åæ ¹æ®å®é æ åµè§£å³é®é¢ï¼
éè¿ä¸å¾å¯ä»¥çå°æ¬å°æå¡ä¸ææç线ç¨åç¸å ³ç¶æï¼å¦æ线ç¨åºç°é®é¢éè¦ææ¥æ¶ï¼éè¦æ¥çå ·ä½æ§è¡çæ¹æ³ï¼é£ä¹å°±éè¦å¿«ç §æ¹å¼æ¥çï¼å ·ä½æ¹å¼å¦ä¸ï¼
ç¹å»æ½æ ·å¨ï¼ç¶åéæ©CPUæ½æ ·ï¼ç¹å»åæ¢ï¼å¨ç¹å»ä¸é¢çå¿«ç §æé®ï¼å°±å¯ä»¥è·åææææ线ç¨çä¸æ¬¡å¿«ç §ï¼ç¶åå°±å¯ä»¥çå°æ¯ä¸ªçº¿ç¨æ§è¡çæºç ï¼å ·ä½æä½å¦ä¸å¾ï¼
éè¿ä¸è¿°çæä½å³å¯æ¥ç线ç¨å ·ä½æ¶åçæºç ï¼ä»èææ¥é®é¢ï¼
ä¸é¢è¯´çæ¯æ¬å°æå¡çæµï¼ä½æ¯æå¾å¤æ åµæ¬å°æå¡æ¯ææ¥ä¸å°é®é¢çï¼åªæå¨æå¡å¨ä¸é¢æè½çåºé®é¢ï¼é£ä¹æ们就éè¦è¿ç¨è¿æ¥æå¡å¨ä¸é¢æå¡ï¼è¿è¡çæ§ï¼æ¥çå ·ä½çº¿ç¨çè¿è¡æ åµåæºç åæ
è¿ç¨é ç½®éè¦å¨å¯å¨Javaæå¡çæ¶åï¼å¨å¯å¨å½ä»¤ä¸é¢æ·»å æå®å¯å¨åæ°ï¼è¿éæä¾çå½ä»¤æ¯æ£å¸¸æ åµä¸å®æ´çå¯å¨jarå çå½ä»¤ï¼å ·ä½å½ä»¤åæ°ä¹å¾æ¸ æ¥ï¼å½ä»¤å¦ä¸ï¼
ps:portæ¯çæ§æéç端å£ï¼ä¹å°±æ¯å¯å¨æå¡æå®ç端å£ï¼ä½æ¯ç«¯å£è¦å¯¹å¤å¼æ¾ï¼ä¸è¬çæ®éæå¡ç«¯å£æ¯ä¸ä¼å¯¹å®å¼æ¾çï¼è¿ä¸ç¹éè¦æ³¨æ
hostnameæ¯å¯¹åºçæ§çipï¼æè¿éç¨çå°±æ¯æå¡å¨ipï¼å¦æè¿æ¥ä¸ä¸çæ åµä¸ï¼å¯ä»¥å°è¯ä½¿ç¨ hostname -i è·åç对åºipï¼å ·ä½æ åµå ·ä½åæ
ç¶åå¯å¨æå¡ä¹åï¼éä¸è¿ç¨å³é®æ·»å è¿ç¨ä¸»æºï¼è¾å ¥è¿ç¨ä¸»æºipåç¡®å®å³å¯ï¼ç¶åéæ©ä¸»æºipï¼å³é®æ·»å JMXè¿æ¥ï¼è¾å ¥è®¾å®ç端å£å·ï¼ç¹å»ç¡®å®å³å¯ï¼ç¶åå°±å¯ä»¥çæ§è¿ç¨æå¡å¨äºï¼æ¥ä¸æ¥çæ¥ç线ç¨çæ åµãçæ§æå¡æ åµåææ¥é®é¢ä½¿ç¨å¿«ç §ï¼å°±åä¸é¢æ¬å°çæä½ä¸æ ·äºï¼
ç»è¿ä¸è¿°æä½å°±å¯ä»¥éè¿JDKèªå¸¦ççæ§è½¯ä»¶ï¼è¿è¡çæ§Javaç¨åºçè¿è¡æ åµä»¥åæå¡å¨çè¿è¡æ åµå¦ï¼
æ¬äººåèï¼å¦æé®é¢æ¬¢è¿å¤§å®¶ææ£ï¼å ±åè¿æ¥ï¼
JVM角度看方法调用-MethodHandle篇
在我们日常编程中,方法调用主要涉及三种方式:直接调用、反射调用、以及 MethodHandle 调用。这一系列文章旨在深入探讨这三种调用方式的原理和性能分析,文章基于 JDK 1.8 版本进行阐述。在前一篇文章中,我们总结了反射调用的诸多缺点,影响性能,因此建议在热点代码中使用 MethodHandle 替代反射调用。通过与极致优化后的反射调用进行比较,我们发现 MethodHandle 在性能和直接调用方面几乎不相上下,这背后的原因是通过深入剖析 HotSpot 源码得以揭示。
接下来,我们逐一揭开 MethodHandle 的神秘面纱。首先,让我们明确,MethodHandle 是一个强类型的引用,能够直接执行,类似于反射中的 Method 类,是对目标方法的引用。它被比喻为函数指针,可以指向静态方法或实例方法、构造器或字段。MethodHandle 的执行通过 `invoke` 和 `invokeExact` 方法实现,其中 `invokeExact` 要求参数类型与底层方法的参数完全匹配,而 `invoke` 在参数类型不匹配时会做适当的调整,如包装类型。
MethodHandle 在 JDK 7 中首次引入,其相关核心类包括 MethodType 和 MethodHandles.Lookup。MethodType 用于确认方法句柄是否适配,由所指向方法的参数类型和返回类型组成;MethodHandles.Lookup 用于创建方法句柄,提供多个 API,既可以使用反射 API 中的 Method 来查找,也可以根据类、方法名以及方法句柄类型来查找。
在实际应用中,我们可以通过以下例子创建 MethodHandle 并进行方法调用。例如,尝试在外部类 MethodHandleDemo 中调用 Animal 类中的私有方法 calculation(int one, int two)。若直接使用反射调用,可能会遇到外部类无法访问 Animal 类中私有方法句柄的异常。然而,通过修改 MethodHandles.Lookup 的获取方式,改为调用 Animal 中的 getLookup() 方法,此时外部类可以正常调用私有方法,说明方法句柄的访问权限不取决于句柄的创建位置,而是取决于 Lookup 对象的创建位置。
MethodHandle 在设计时就将方法修饰符权限检查放在了通过 MethodHandles.Lookup 获取 MethodHandle 的阶段,而调用时则不会进行权限检查,避免了重复的开销。这正是 MethodHandle 相对于反射调用的一个显著优势。
接下来,我们深入探讨 MethodHandle 调用的原理。首先,我们关注 MethodHandle 的动态签名。在编译时,javac 会对 MethodHandle 的 `invoke` 方法进行动态签名处理,与普通的 `invokevirtual` 指令不同,它根据实际参数和返回类型派生符号类型描述符。此外,通过 @PolymorphicSignature 注解,可以实现多态签名处理。进一步执行时,若签名不一致,会抛出异常。
然后,我们解释了 `invoke` 方法的调用实际上不是通过 JNI(Java Native Interface)进行 native 方法调用,而是执行 `invokehandle` 指令。这一过程发生在类加载阶段,JVM 会扫描类中的所有方法,对字节码进行优化,将 `invokehandle` 指令重写为其他指令,从而实现 MethodHandle 的内联优化。这一机制同时解答了为什么 MethodHandle 虽然是一个 native 方法,却可以被 JIT(Just-In-Time)编译器进行内联优化的问题。
在解释 `invokehandle` 指令后,我们分析了如何从 `MethodHandle.invoke()` 调用到实际执行的 Java 代码中的 `java.lang.invoke.LambdaForm$MH/.invoke_MT()` 方法。通过剖析 HotSpot 源码,我们发现 `invokehandle` 指令执行时会调用 `java.lang.invoke.MethodHandleNatives::linkMethod()` 方法,该方法返回一个 `MemberName` 对象,该对象描述了一个具体的方法。通过 `MemberName` 对象,JIT 可以直接访问方法的实现,从而避免了后续的解析过程,实现了高效的调用。
我们还探讨了 `final` 关键字对 MethodHandle 性能的影响。标记为 `final` 的 MethodHandle 可以被更有效地内联,从而更接近直接调用的性能。通过分析 `MethodHandle.invoke()` 调用栈以及 HotSpot 源码,我们发现 `final` 关键字的使用与否,直接关系到后续调用栈链路能否被内联,从而影响性能。
最后,我们注意到在 `MethodHandle` 的调用链路中,某些关键步骤,如 `linkMethod`,会在第一次调用时执行,之后的调用则从常量池中获取缓存。理解这些细节有助于我们更好地优化代码性能,尤其是在涉及大量方法调用的场景中。
这究竟是为什么呢?都说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算法,这个差值可能有所不同。