工程师java
凌晨两点,工程张工盯着屏幕上的工程StackOverflow页面,报错信息是工程`java.lang.OutOfMemoryError: GC overhead limit exceeded`。这已经是工程他这周第三次遇到堆内存溢出。他骂了句脏话,工程把`-Xmx`参数从2g调到4g,工程重新跑了一遍压测脚本。工程十分钟后,工程服务又挂了。工程 这不是工程段子。任何一个写过三年以上Java的工程人,都经历过这种时刻。工程Java工程师的工程日常,很大一部分时间不是工程在写业务代码,而是工程在跟JVM较劲。堆内存、栈内存、元空间、GC日志——这些东西在学校里没人教,进了公司也没人系统讲,全靠线上事故喂出来。 我刚入行那会儿,觉得Java就是写写Spring Boot的Controller,调调Service,拼拼SQL。后来才发现,真正区分一个Java工程师水平的,不是会不会用框架,而是出了问题能不能定位到根因。 举个例子。有个同事写的定时任务,每天凌晨跑一次数据同步。上线三个月都正常,第四个月突然开始频繁Full GC。查了半天,发现是某个Map只增不减,每天往里塞几万条记录,攒了三个月终于把老年代撑爆了。代码逻辑本身没错,错在没人想过“这个Map的生命周期到底该多长”。 这种问题,面试的时候不会考,代码Review的时候也容易漏。只有真的跑在生产环境上,被用户投诉了,才会暴露出来。 早些年排查问题,靠的是`jstack`、`jmap`、`jstat`三件套,加上MAT分析堆转储文件。现在好多了,Arthas一挂,`watch`、`trace`、`dashboard`几条命令下去,基本能锁定问题。但工具再好,也得知道往哪儿看。 我见过有人用Arthas的`trace`命令追一个接口,追了半小时没结果——因为他追的是Controller层,而真正的耗时在数据库连接池等待上。工具不会告诉你“该看哪里”,那是经验的事。 说到经验,有个挺有意思的现象。很多Java工程师对框架的版本升级特别敏感,Spring Boot 2.7升3.0能聊一下午,但对自己负责的服务的GC日志从来没看过。问就是“没出过问题”。等出问题的时候,往往就是P0级事故。 Java写久了,会形成一些肌肉记忆。比如看到`for`循环里拼接字符串,手会自动改成`StringBuilder`;看到`SimpleDateFormat`,脑子里会蹦出“线程不安全”四个字;看到`@Transactional`,会下意识检查方法是不是`public`的。 但肌肉记忆也有副作用。有一次我写了个`ArrayList`的遍历删除,用了`Iterator`,觉得没问题。结果代码Review的时候,一个刚毕业的同事问我:“为什么不用`removeIf`?一行就够了。”我愣了两秒,确实,Java 8都出来这么多年了,有些习惯该改改了。 技术栈这东西,更新太快。五年前还在用Struts2的团队,现在可能已经在写Quarkus了。但底层的东西变化没那么快——JVM的内存模型、并发包的设计思想、Spring的IoC容器原理,这些搞明白了,上层框架怎么换都不慌。 如果你是个Java工程师,别只盯着业务代码。花点时间看看GC日志,学学Arthas的常用命令,读读JDK源码里`HashMap`和`ConcurrentHashMap`的实现。这些东西不会让你立刻升职加薪,但会在某个凌晨两点,当你面对一个诡异的线上问题时,让你少掉几根头发。 张工后来把那个Map改成了Guava的Cache,设置了过期时间。问题解决了。他在群里发了句“搞定了”,然后关掉电脑,窗外天已经亮了。那些年我们踩过的坑
工具链的进化
写代码这件事
最后说点实在的
-
上一篇
-
下一篇
- 随机阅读
- 搜索
-
- 友情链接
-