自后我知道了:认禽蛋怂越晚

发布日期:2024-05-02 08:29    点击次数:124

自后我知道了:认禽蛋怂越晚

 禽蛋[[410405]]

JVM 对 Java 有多进犯,对设施员口试有多进犯,这些无须多说。

要是你还没意志到学 JVM 的必要性,或者不知谈怎么学 JVM,那么看完这篇著述,你就能知谈谜底了。

也曾的我很不屑于学 JVM,然而自后发现不学不行。这就像和媳妇吵架之后我不想谈歉相似,不谈歉那是不可能的,谈歉是夙夜的事儿,逃不掉。

自后我知道了:

认怂越晚,结局越惨。

然而我学的时候才知谈:JVM,你太过分了,太难学了!

我的学习历程不错说终点陡立,不外资历陡立之后,我倒是发现学 JVM 的门谈好多。

以我的教训加上和同业们的交流,我认为学 JVM 最好的步履是:

在设施员不同的水平段,作念精确的学习。

烟台鹏洋国际贸易有限公司

所谓的精确学习,等于学习对我方责任有弘大匡助的常识点。以责任执行带动学习,比及积贮多了,再一举攻克通盘 JVM 常识点,最终熟练掌执 JVM 底层旨趣。

底下我来说说低级、高等、资深设施员,如何顺序渐进、分步学习。

低级设施员怎么学

对刚入行的外行设施员,责任一般是成立浅易 bug、蛊惑浅易功能。如何编码少出 bug,是这个阶段的中枢问题。

关于这个中枢问题,JVM 旨趣必须长远掌执两个常识点。

1. 类的运行化

类的运行化,要了解的终点长远才不错。否则,一不督察就会往名堂里引入一些关连运行化的 bug。

比如望望底下这段代码:

public class ParentClass {     private int parentX;     public ParentClass() {         setX(100);     }     public void setX(int x) {         parentX = x;     } }  public class ChildClass extends ParentClass{     private int childX = 1;     public ChildClass() {}     @Override     public void setX(int x) {         super.setX(x);         childX = x;         System.out.println("ChildX 被赋值为 " + x);     }     public void printX() {         System.out.println("ChildX = " + childX);     }  }  public class TryInitMain {     public static void main(String[] args) {         ChildClass cc = new ChildClass();         cc.printX();     } } 

有利思意思不错运行望望着力,一朝把这种代码放到了分娩环境里,排查终点坚苦。

2. Java 内存结构和对象分派

第二个常识点,等于 Java 内存结构和对象分派的基础常识,尤其是 JVM 内存中堆的布局和对象分派的关系。

比如,堆内存的布局

天然,Java7 后,新布局变了

知谈布局了,就得知谈java对象分派的基本原则:

对象优先在Eden折柳派 对象太大径直会分派到老年代

只好知谈这些常识,才不会频频写下底下这种 bug:

// 将全部行数读取的内存中  List<String> lines = FileUtils.readLines(new File("temp/test.txt"), Charset.defaultCharset());  for (String line : lines) {      // pass  }  

上头这段代码,一朝读取到了大文献,很可能把分娩环境搞崩。

是以,把上述两个常识点长远意会了,对外行进步我方的代码质料终点终点灵验。只好代码质料上去了,你才能获取更好的发展。

关于这两个常识点,我认为通过聚集的著述去学习最好。要是径直看书,有两个最大的过失:

常识积贮不及导致学不懂 书中冗余常识点太多,相互交杂,元气心灵耗尽过大,性价比不高

故这里学习保举凭证常识点去搜著述读,而不是找旨趣性的竹素看。

高等设施员怎么学

对处于这个阶段的一又友,他们还是不错熟练编写健壮的代码了,频频会独处蛊惑出一个大的功能模块,有的可能还能独处蛊惑出一个无缺的微型名堂。

这时候,他们可能会濒临两种情况:

1. 需要写一些器具类给全团队使用

在这种情况下,你很可能就需要 Java 中的语法糖,因为语法糖能让你写出终点天真浅易的代码。这包括泛型,自动拆装箱,可变参数还有遍历轮回。

然而,使用这些语法糖的时候,要是你不闇练他们在 JVM 中的完毕旨趣,就终点容易栽个大跟头,

比如:

public class GenericPitfall {     public static void main(String[] args) {       List list = new ArrayList();       list.add("123");       List<Integer>  list2 = list;       System.out.println(list2.get(0).intValue());   } } 

2. 编写性能优厚的代码

什么时候需要性能优厚的代码?最常见的等于把过去性能不好的同步完毕,转念成异步完毕。

而这种要求,就需要蛊惑对 Java 的多线程蛊惑终点闇练,况兼一定要长远意会多线程在 JVM 中的旨趣完毕。

否则,不错望望底下这段代码:

class IncompletedSynchronization {   int x;    public int getX() {       return x;   }    public synchronized void setX(int x) {       this.x = x;   } } 

再望望这段:

Object lock = new Object(); synchronized (lock) {   lock = new Object(); } 

要是把上头这些代码上了分娩环境,熬今夜排查问题的运谈就注定了……

这里的常识点,我保举通过网上的著述看,又因为波及到了并发常识,我冷漠就着《Java Performance》第二版的“Chapter 9. Threading and Synchronization Performance”这章一都看。

还多余力,冷漠再连续看周志明的那本《长远意会 JAVA 造谣机》第三版中的 12-13 章。周志明这本书讲的十分长远,也带来个过失:门槛高。此时,要是没看懂不错放一放。

堤防,我这里说的是并发的旨趣,不是并发实施,读者想学并发编程,湛江市洁名石膏有限公司《JAVA 并发编程实施》我认为是前纲领求, 鹿邑县立棉类有限公司故不会赘述。

资深设施员怎么学

这时候的你, 汉寿县和记客家菜餐馆还是动手承担名堂蛊惑中很进犯的职责了, 浑源县所加壁纸有限公司有些出色的一又友都动手带团队了。那这时候, 台州市椒光照明有限公司你可能会作念底下的事:

1. 合理斟酌名堂使用资源

合理斟酌名堂使用资源,前提是对垃圾回收有终点长远的了解。

要是说在外行期,还是对 Java 对象的内存分派和内存使用有了大约的认识,那么,这个垃圾回收,则是这类常识的进一步拓展。

只好意会了各式垃圾回收的旨趣,再合营着 Java 内存布局的基础常识,才能更好地斟酌出名堂用什么回收算法,才能在适宜的资源利费用上获取最好性能。

比如,重生代和老年代之间的适宜比例。比如,重生代中 Eden 和 Survivor 区域间的比例。

2. 排查各式线上问题

要排查各式问题,就需要对 JVM 提供的各式故障排查器具终点了解。

这些器具又分为两类:

基础的号令行形势的故障处理器具,比如 jps、jstack 等等 第二类是可视化的故障处理器具,比如 VisualVM

然而,掌执器具的使用还不够。因为关连垃圾回收的问题,还必须得通过贯通 GC 日记后,再通过器具的使用,才可能能定位到问题的根源。

是以,最好对使用故障排查器具和 GC 日记都终点熟练。

比如:

2021-05-26T14:45:37.987-0200: 151.126: [GC (Allocation Failure) 151.126: [DefNew: 629119K->69888K(629120K), 0.0584157 secs] 1619346K->1273247K(2027264K), 0.0585007 secs] [Times: user=0.06 sys=0.00, real=0.06 secs]  2021-05-26T14:45:59.690-0200: 172.829: [GC (Allocation Failure) 172.829: [DefNew: 629120K->629120K(629120K), 0.0000372 secs]172.829: [Tenured: 1203359K->755802K(1398144K), 0.1855567 secs] 1832479K->755802K(2027264K), [Metaspace: 6741K->6741K(1056768K)], 0.1856954 secs] [Times: user=0.18 sys=0.00, real=0.18 secs] 

上头这条,应该一眼看出来,垃圾算法用的是 Serial 聚集器,况兼年青代分派出现了问题,大小可能需要更变。

这里的常识点,狠恶反对看网上的著述,网上说的好多细节有问题,禽蛋冒昧好多。是以,保举看书。

《Java Performance》第二版里,“Chapter 5. An Introduction to Garbage Collection”,“Chapter 6. Garbage Collection Algorithms”的常识还是鼓胀。

有东谈主去看《长远意会 JAVA 造谣机》第三版中的第 3 章,讲垃圾聚集器与内存分派计策的。这里如故老问题,讲的太细,我冷漠绕过 3.4 节,讲 HotSpot 算法细节的那块儿。

这里安全点这个常识点挺进犯,然而当今这个阶段想意会挺难的。我以为改日作念一些底层框架,斗争到崩溃还原的 checkpoint 联牵挂牵想了,再回头来学习,那才能真确意会和掌执。

时候巨匠怎么学

达到这个级别了,那就需要对整套 JVM 要有终点长远的了解了,因为你是解决时候问题的临了保险了。有些时候,致使还需要因为某些问题蛊惑出各式种种的器具。

也曾,有个名堂频频常老是会报错:

java.lang.OutOfMemoryError: GC overhead limit exceeded 

这个问题几个共事都没处理,就来找我。我看了看,霎时想起来,过去在官方调优指南《HotSpot Virtual Machine Garbage Collection Tuning Guide》看到过联系先容。

JVM 自己内存不及就会运行 GC,然而要是每次 GC 回收的内存不够,那么很快就会动手下一次 GC。

JVM 有个默许的保护机制,要是发当今一个统计周期内,98% 的时刻都是在运行 GC,内存回收却少于 2% 的时候,就会报这个错。

怎么引起的呢?这个问题要是去排查代码,那竟然是难如登天,最初,莫得任何堆栈极度去匡助定位问题。其次,名堂代码量大了去了,而且是年初久远。

这时,就需要通过对 JVM 总体的长远意会,去反推问题了。我其时是这么推理的:

内存溢出,GC 无法回收问题,讲明了两个问题:

堆内的内存不够用了 占用内存的对象要么等于该关闭的资源没关连闭,要么被多数的暂时放在一都了

那要是我 dump 出内存文献出来,再分析下就知谈是哪些对象在占用内存了。

一查发现是多数的字符串在占用内存。

概述我前边的计算,字符串不是数据库鸠合,细目莫得该关闭未关闭的问题。那就剩一个可能了,等于被多数的暂时放起来了,导致 GC 回收不了。

那么新问题来了,能多数放字符串的,会是什么?

最初就去猜缓存。凭证这条陈迹,径直去源码搜 Cache 关节词,把所关连于 Cache 的代码都看了下。一下子就找到问题了。

本来,我们有个功能是贯通一个终点大的文献。文献的模样如下:

需要把这个文献的每一瞥执行按照列去一都存到数据库里。

由于写代码的东谈主偷懒,想一次贯通完毕后一股脑全塞到数据库里。是以,他弄了个 Map,Map 的 Key 是调换的列名,Value是每一瞥贯通过的执行。

而这么写代码的着力等于,一瞥对应了一个有三个条主见 HashMap。要是文献有十几万行,就有十几万的 HashMap。然后,这些 HashMap 再存到一个列内外,再把这个列表放到一个叫作念 xxxCache 的 HashMap 中。

表示代码如下:

public class ParseFile4OOM {     public static void main(String[] args) {         List<Map<String, String>> lst = new ArrayList<>();         for (int i = 0; i < 100000; i++) {             Map<String, String> map = new HashMap<>();             map.put("Column1", "Content1");             map.put("Column2", "Content2");             map.put("Column3", "Content3");             lst.add(map);         }          Map<String, List<Map<String, String>>> contentCache = new HashMap<>();         contentCache.put("contents", lst);     } } 

那对这种情况怎么办呢?代码还不成大动,只可优化。

那时,我们还是用了 JDK8 了,引入了 String 常量池。同期,Hashmap 在这个业务场景下,容积是固定的,是以,就不应该给它多分派空间,就固定死为 3。

首页-微园宏地板有限公司

优化后,代码如下:

public class ParseFile4OOM {     public static void main(String[] args) {         List<Map<String, String>> lst = new ArrayList<>();         for (int i = 0; i < 100000; i++) {             Map<String, String> map = new HashMap<>(3);             map.put("Column1".intern(), "Content1".intern());             map.put("Column2".intern(), "Content2".intern());             map.put("Column3".intern(), "Content3".intern());             lst.add(map);         }          Map<String, List<Map<String, String>>> contentCache = new HashMap<>();         contentCache.put("contents".intern(), lst);     } } 

把优化后的代码上线,极度处理了!

是以,在这个阶段就非得把 JVM 吃透不可了。吃透旨趣就必须靠看书了。

周志明的《长远意会 JAVA 造谣机》是必须的了,然而还不够。

《Oracle JRockit: The Definitive Guide》这本书我也冷漠读一读,天然老了,然而内部的好多执行,尤其前四章,对 JVM 旨趣竟然快讲透了。对 JVM 是如何弹性伸缩去均衡资源和性能关系的,娓娓谈来,让我翻然醒悟,编程视线一下子绽放了好多。

至此,不同阶段的学习步履讲罢了。

总的来说,JVM 常识广博复杂,要是想要掌执,不成一蹴而就。而且我们设施员阻遏易,需要学的常识太多,关联词我们的元气心灵却是有限的。

是以,关于 JVM 旨趣来说,假定有些常识点咫尺看不懂,用不上,不错先暂时放一放,作念到精确学习,把省下来的元气心灵用在别的常识致使我方的生涯上,更有酷爱。

看完要是以为有收成,但愿能帮衬转发、顺手点个在看,你的维持对我很进犯。

你好,我是四猿外。

一家上市公司的时候总监,不休的时候团队一百余东谈主。

我从又名非筹办机专科的毕业生,转行到设施员,一齐打拼,一齐成长。

本文转载自微信公众号「四猿外」,不错通过以下二维码原宥。转载本文请研讨四猿外公众号。

 



上一篇:没有了
下一篇:没有了