NullPointerException in Java with no StackTrace

这周一个项目遇到一个问题,同事查看日志发现抛出:NullPointerException,却没有堆栈信息,然后同事感觉很奇怪,因为打日志的方法,打印的确实是:e,而不是很多人不明所以的打印的:e.getMessage()。然后我看了一下想起来我看过某本书上说过的,JIT 优化。当某个异常抛出很多次之后,由于 Java 虚拟机 JIT 优化,会省略堆栈信息。往上面翻日志肯定可以会找到报错的地方,当然会出现报错的信息太多,比较难翻。写这篇文章的本来想找找那本书,参考一下的,结果忘了是那本书了,一时没找到,不过这个问题虽然不是非常常见,但是网上还是有很多说明的,所以就简单说说 JVM 有一个参数:OmitStackTraceInFastThrow 来控制是否开启此优化。关于此参数的简单说明: JVM参数-XX:-OmitStackTraceInFastThrow参数可以关掉JVM对堆栈信息的优化。如果设置了这个参数,那么异常堆栈就能完整输出了。 “在服务器中的VM编译器现在提供准确的所有的“冷”内置异常堆栈回溯功能。为了性能考虑,当这些异常被抛出很多次时,这个方法会被重新编译,此后编译器将使用一种更快的抛出异常的方式,即抛出预先分配好的不带堆栈信息的异常。要完全关闭掉这种预分配的异常,就需要使用-XX:-OmitStackTraceInFastThrow参数。” 相关stackoverflow讨论:https://stackoverflow.com/questions/2411487/nullpointerexception-in-java-with-no-stacktrace 笨神小程序 JVMPocket 对此参数的解释截图: 另,看到网上有部分人建议关闭此参数,个人是建议的: 由于Java 在虚拟机中运行,天生是比 c 要慢的,为了优化此问题,那些 JVM 大神们搞出了 JIT 优化,对性能有了大幅提升。 异常信息使我们应该特别关注了,当出现了异常应该尽快发现问题解决问题,而不是这个异常发生很多次了但是一直不知道。 打详细堆栈信息是很影响性能的,如果这个异常出现很多次了,没必要每次都打出来异常,看一个地方就知道了,而不是让他一直打,影响性能。 那有人说了当遇到此问题时,堆栈信息看不到,日志又比较难翻怎么办?我们好像也不能动态的添加 JVM 的启动参数,所以保险起见还是关闭此参数。个人认为:这个异常这么常出现,而且是 JIT 的优化导致看不到堆栈信息了,可以找一台机器重启一下就好了,没必要因小失大,我们从笨神的小程序也可以看到 JVM 默认是开启此参数的,开启肯定是有其道理的。

January 7, 2018 · 1 分钟 · Bridge Li

你假笨JVM参数 – 007 UseGCLogFileRotation NumberOfGCLogFiles GCLogFileSize

你假笨的第七次分享,也是你假笨在 2017 年的最后一次关于 JVM 的分享: 序号:007 时间:2017-08-10 参数: -XX:UseGCLogFileRotation -XX:NumberOfGCLogFiles -XX:GCLogFileSize 含义: 这次分享了3个设置滚动记录GC日志的参数 通过参数-Xloggc:xxx可指定GC日志文件路径 普通情况下,GC日志文件内容会不断积累,进程重启后日志文件会被覆盖 这次分享的3个参数在设置-Xloggc参数的前提下有效 -XX:UseGCLogFileRotation Enabled GC log rotation, requires -Xloggc. 打开或关闭GC日志滚动记录功能,要求必须设置 -Xloggc参数 -XX:NumberOfGCLogFiles Set the number of files to use when rotating logs, must be >= 1. The rotated log files will use the following naming scheme, .0, .1, …, .n-1. 设置滚动日志文件的个数,必须大于1 日志文件命名策略是,.0, .1, …, .n-1,其中n是该参数的值 -XX:GCLogFileSize The size of the log file at which point the log will be rotated, must be >= 8K. 设置滚动日志文件的大小,必须大于8k 当前写日志文件大小超过该参数值时,日志将写入下一个文件 ...

December 31, 2017 · 1 分钟 · Bridge Li

你假笨JVM参数 – 006 ExplicitGCInvokesConcurrent

你假笨的第六次分享: 序号:006 时间:2017-07-31 参数:-XX:ExplicitGCInvokesConcurrent 含义: Enables invoking of concurrent GC by using the System.gc() request. This option is disabled by default and can be enabled only together with the -XX:+UseConcMarkSweepGC option. System.gc()是正常FULL GC,会STW 打开此参数后,在做System.gc()时会做background模式CMS GC,即并行FULL GC,可提高FULL GC效率 注,该参数在允许systemGC且使用CMS GC时有效 举例: -XX:+ExplicitGCInvokesConcurrent 相关参数: -XX:DisableExplicitGC 控制是否允许System.gc(),默认允许 小程序截图: 分享记录:

December 23, 2017 · 1 分钟 · Bridge Li

你假笨JVM参数 – 005 CMSScavengeBeforeRemark

你假笨的第五次分享: 序号:005 时间:2017-07-24 参数:-XX:CMSScavengeBeforeRemark 含义: Enable scavenging attempts before the CMS remark step. 开启或关闭在CMS重新标记阶段之前的清除(YGC)尝试 CMS并发标记阶段与用户线程并发进行,此阶段会产生已经被标记了的对象又发生变化的情况,若打开此开关,可在一定程度上降低CMS重新标记阶段对上述“又发生变化”对象的扫描时间,当然,“清除尝试”也会消耗一些时间 注,开启此开关并不会保证在标记阶段前一定会进行清除操作 小程序截图: 分享记录:

December 17, 2017 · 1 分钟 · Bridge Li

你假笨JVM参数 – 004 MaxTenuringThreshold

你假笨的第四次分享: 序号:004 时间:2017-07-21 参数:-XX:MaxTenuringThreshold 含义: Sets the maximum tenuring threshold for use in adaptive GC sizing. The largest value is 15. The default value is 15 for the parallel (throughput) collector, and 6 for the CMS collector. 在可自动调整对象晋升老年代年龄阈值的GC中,该参数用于设置上述年龄阈值的最大值 参数值最大为15 Parallel Scavenge中默认值为15,CMS中默认值为6,G1中默认值为15 小程序截图: 分享记录:

December 10, 2017 · 1 分钟 · Bridge Li

你假笨JVM参数 – 003 CompileCommand

你假笨的第三次分享: 序号:003 时间:2017-07-19 参数:-XX:CompileCommand 含义: Specifies a command to perform on a method. 该参数用于定制编译需求,比如过滤某个方法不做JIT编译 若未指定方法描述符,则对全部同名方法执行命令操作,具体如何指定见下文[举例] 可使用星号通配符(*)指定类或方法,具体如何使用见下文[举例] 该参数可多次指定,或使用 换行符(\n)分隔参数后的多个命令 解析完该命令后,JIT编译器会读取.hotspot_compiler文件中的命令,该参数也可写在.hotspot_compiler文件中 可使用-XX:CompileCommandFile指定.hotspot_compiler文件为其他文件 用法: -XX:CompileCommand=command,method[,option] 命令: exclude,跳过编译指定的方法 compileonly,只编译指定的方法 inline/dontinline,设置是否内联指定方法 print,打印生成的汇编代码 break,JVM以debug模式运行时,在方法编译开始处设置断点 quiet,不打印在此命令之后、通过-XX:CompileCommand指定的编译选项 log,记录指定方法的编译日志,若未指定,则记录所有方法的编译日志 其他命令,option,help 举例: 设置编译器跳过编译com.jvmpocket.Dummy类test方法的4种写法 -XX:CompileCommand=exclude,com/jvmpocket/Dummy.test -XX:CompileCommand=exclude,com/jvmpocket/Dummy::test -XX:CompileCommand=exclude,com.jvmpocket.Dummy::test -XX:CompileCommand="exclude com/jvmpocket/Dummy test" 设置编译器只跳过编译java.lang.String类int indexOf(String)方法 -XX:CompileCommand=“exclude,java/lang/String.indexOf,(Ljava/lang/String;)I” 设置编译器跳过编译所有类的indexOf方法 -XX:CompileCommand=exclude,*.indexOf 小程序截图: 分享记录:

November 25, 2017 · 1 分钟 · Bridge Li

MySQL : The last packet successfully received from the server was XXX milliseconds ago

14年毕业写完论文没事干的时候,自己玩微信公众号开发,当时想做一个自然语言交互,其实就是想试一下lucene,但是当时建索引的时候偶尔会报这个错,一致不知道具体原因,去网上搜索但是天下文章一大抄,你抄我来我抄他,也没找到原因,后来因为工作中也没遇到过,感觉应该是自己当时水平不行就忘了这件事,前几天 fatsjson 和 druid 的作者温少突然在一个群里面说有人通过阿里工单反馈这个问题,他给追踪了一下,找到了原因,原来还是还是有人遇到这个问题,今天记录一下,希望对遇到这个问题的小伙伴有帮助,报错的信息大概就是: Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 20,820,001 milliseconds ago. The last packet sent successfully to the server was 20,820,002 milliseconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem. at sun.reflect.GeneratedConstructorAccessor29.newInstance(Unknown Source) ………… 下面是温少分享的截图 ...

November 11, 2017 · 1 分钟 · Bridge Li

你假笨说JVM参数 – 002 StringTableSize

没想到距离第一次整理你假笨的分享已经过去两个多月了,近期会继续整理一系列你假笨关于JVM参数的分享,下面是第二次: 序号:002 时间:2017-07-14 参数:-XX:StringTableSize 含义:Number of buckets in the interned String table String.intern() 被调用时会往 Hashtable 插入一个 String(若该 String 不存在),这里的 Table 就是 StringTable,此参数就是这个 StringTable 的大小,若此参数设置过小,明显的问题就是过多的hash碰撞,造成在查找字符串时比较消耗 CPU 资源 JDK 1.6 起,当冲突次数超过 100 次会自动 rehash,即便如此,若此参数设置过小会导致不断的 rehash,依然会过度消耗 CPU 资源 建议将此参数设置的值稍大一些,以减少 hash 冲突 使用方法:-XX:ReservedCodeCacheSize=__ 小程序截图: 分享记录: 感谢你假笨

November 5, 2017 · 1 分钟 · Bridge Li

程序员都应该懂点开源许可协议

最近 Facebook 开源的 React 的开源协议专利条款一事闹得沸沸扬扬,著名的 WordPress、百度等纷纷声明弃用 React,最终 Facebook 听从大众的声音改回了BSD,这就牵涉到一个如何选择开源协议的问题,因为 React 是一个生态,所以这事影响比较大,其实之前有很多关于开源协议用错导致原作者利益受损的事,例如前两个月就有一个被雷军称赞的称为最牛的 00 的 CEO 的公司抄袭别人代码连素材都不修改的案例,所以想到之前曾看到有一个乌克兰程序员 Paul Miller 制作了一张图,一分钟明白你应该选择哪个开源协议,原图如下: 原文地址:http://paulmillr.com/posts/simple-description-of-popular-software-licenses/ 如果英文不好的话(其实我英文更不好,但连猜带蒙也看了个差不多),有热心网友翻译了一个中文版,地址:http://blog.csdn.net/wadefelix/article/details/6384317 多说一点: 记得刚实习的时候,老大强调不准使用任何未经公司批准的任何软件,如果需要必须报备,经相关人员同意后方可使用,当时不明白为什么,其实看看 GPL 协议也就猜到了。另外刚开始玩 GitHub 的时候,以为就随便把代码放上去就完事了,当然代码写的很烂也不会被人使用,但严格意义上来说还是应该选择一个开源协议的,据说 GitHub 目前有相当数量的项目没有添加开源协议,所以为了使开发者养成选择开源许可证的习惯,GitHub 现在在创建新库的表单中添加了一个许可证选项。该选项中提供了一组简化的开源许可证,开发者选择后,Github 会自动在其库的根目录中创建一个 LICENSE 文件。 最后为了维护开源社区的健康发展,同时不致自己的利益受损,大家一定注意选择合适的开源协议。

October 1, 2017 · 1 分钟 · Bridge Li

是的,我也开启了全站HTTPS

现在的趋势都在全站HTTPS,据说在Google内部有一个时间表,会把所有未开启HTTPS的网站标注为不安全(目前仅仅会把带密码框的输入页标注为不安全),所以一直想玩玩,去年的时候就看到新浪timyang的博客开启了全站HTTPS,并写了一篇文章如何开启,当时就想玩玩,但感觉还是稍有麻烦,而且当时的博客服务器用的Apache,对Apache配置不熟,想着是自己的小博客就没动,前几天突然看到coolshell网也开启了全站HTTPS,发现现在配置变得很简单了,而且我的博客服务器也由Apache换成了Nginx,所以就玩了玩,确实很方便。 首先声明,无论是timyang还是左耳朵耗子,使用的都是Let’s Encrypt,他是一个公益组织,表示感谢,网址:https://letsencrypt.org/ 下面写一下开启的方法: 首先,打开 https://certbot.eff.org 网页。 在那个机器上图标下面,你需要选择一下你用的 Web 接入软件 和你的 操作系统。比如,我选的,nginx 和 CentOS 6。 然后就会跳转到一个安装教程网页。你就照着做一遍就好了。 例如我选的这个调到安装教程页,出现的命令是: wget https://dl.eff.org/certbot-auto chmod a+x certbot-auto 然后,运行如下命令: ./path/to/certbot-auto -nginx certbot-auto 会自动检查到你的 nginx.conf 下的配置,把你所有的虚拟站点都列出来,然后让你选择需要开启 https 的站点。你就简单的输入列表编号(用空格分开),因为我的就一个所以直接回车就好了(里面有一些需要你填写的东西,连我这英文巨差的人都可以看懂,相信大家都能看的懂),然后,certbot-auto 就帮你下载证书并更新 nginx.conf 了。 但在这个过程中需要注意的一点:记得开启你的 443 端口,我博客用的阿里云,当时没开启直接报错了,开启之后重新执行一下这个命令就好了。 你打开你的 nginx.conf 文件 ,你可以发现你的文件中的 server 配置中可能被做了如下的修改: listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/www.bridgeli.cn/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/www.bridgeli.cn/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot 和 if ($scheme != "https") { return 301 https://$host$request_uri; } # managed by Certbot 另外开启HTTPS之后都建议开启HTTP/2性能更好,但这要求你的Nginx版本要大于 1.9.5 ,开启的方法也无比简单,只需要在 nginx.conf 的 listen 443 ssl; 后面加上 http2 就好了。如下所示: ...

September 3, 2017 · 2 分钟 · Bridge Li